Swift: iOS Essentials
URLSession & Networking
import Foundation
// Decodable model
struct Post: Codable, Identifiable {
let id: Int
let title: String
let body: String
let userId: Int
}
// Generic API client
struct APIClient {
let baseURL = URL(string: "https://api.example.com")!
func fetch<T: Decodable>(_ path: String) async throws -> T {
let url = baseURL.appendingPathComponent(path)
var request = URLRequest(url: url)
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse,
(200...299).contains(http.statusCode) else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(T.self, from: data)
}
func post<T: Encodable, R: Decodable>(
_ path: String,
body: T
) async throws -> R {
var request = URLRequest(url: baseURL.appendingPathComponent(path))
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: request)
return try JSONDecoder().decode(R.self, from: data)
}
}CoreData
import CoreData
// PersistenceController (boilerplate for CoreData stack)
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "MyApp")
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores { _, error in
if let error { fatalError("CoreData error: \(error)") }
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
// Fetch & save (in SwiftUI view)
struct NoteListView: View {
@Environment(\.managedObjectContext) private var context
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Note.createdAt, ascending: false)],
animation: .default
) private var notes: FetchedResults<Note>
var body: some View {
List(notes) { note in
Text(note.title ?? "")
}
.toolbar {
Button("Add") { createNote() }
}
}
func createNote() {
let note = Note(context: context)
note.id = UUID()
note.title = "New Note"
note.createdAt = Date()
try? context.save()
}
}UIKit Essentials
import UIKit
// ViewController lifecycle
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
private func setupUI() {
view.backgroundColor = .systemBackground
let label = UILabel()
label.text = "Hello"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
// TableView with diffable data source
class UsersViewController: UIViewController {
enum Section { case main }
var dataSource: UITableViewDiffableDataSource<Section, User>!
let tableView = UITableView()
func configureDataSource() {
dataSource = UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, user in
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = user.name
return cell
}
}
func applySnapshot(users: [User]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, User>()
snapshot.appendSections([.main])
snapshot.appendItems(users)
dataSource.apply(snapshot, animatingDifferences: true)
}
}App Architecture & Best Practices
MVVM: View (SwiftUI/UIKit) → ViewModel (ObservableObject) → Model + Services. Most common SwiftUI pattern.
Dependency injection: pass services via init or environment — avoid singletons for testability
Combine vs async/await: prefer async/await for new code; Combine still useful for reactive chains (debounce, publishers)
Memory management: use [weak self] in closures to prevent retain cycles — especially in delegates and callbacks
UserDefaults: for small preferences. CoreData or SwiftData for structured persistent data.
SwiftData (iOS 17+): new macro-based ORM — @Model class replaces CoreData .xcdatamodel setup
App groups: share data between app and extensions (widgets, share extensions) via shared container
Instruments: use for profiling memory leaks (Allocations), CPU usage, and network activity
TestFlight: distribute betas; App Store Connect for release management
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free