Swift
Fast, safe and made for Apple platforms.
Swift is Apple's language for iOS, macOS, watchOS and visionOS apps. It is fast like C, safe by design, and Apple's MLX and Core ML let Swift apps run AI models right on the device.
Why learn Swift?
If you want to build apps for the more than two billion active Apple devices, Swift is the language. SwiftUI makes building interfaces quick and visual.
- Apple platforms: the native language for iOS and macOS apps.
- Safe and fast: optionals prevent null crashes; code compiles to native speed.
- On-device AI: Core ML, MLX Swift and Apple's Foundation Models framework run models locally.
Set up and run your first program
On a Mac, install Xcode. On Linux or Windows, install the Swift toolchain from swift.org.
swift --version
swift hello.swiftlet name = "Ada"
print("Hello, AI! Welcome to Swift, \(name).")swift package init --type executable for a command-line project.let, var and optionals
let is a constant, var a variable. An optional (String?) may hold a value or nil; unwrap it with if let, guard let or ??.
let layers = 32
var lr = 3e-4
lr /= 2
let params: Int64 = 8_030_000_000
var note: String? = nil
print("\(layers) layers, lr \(lr), FP16 \(Double(params) * 2 / 1e9) GB")
print(note ?? "no note")
if let n = note { print(n.count) }Control flow
for-in loops over ranges and collections. switch must be exhaustive and does not fall through. guard exits early when a condition fails.
for epoch in 0..<3 { print("epoch", epoch) }
let bits = 8
switch bits {
case 32: print("FP32")
case 16: print("FP16")
case 8: print("FP8")
default: print("other")
}
func check(vram: Int?) {
guard let v = vram, v >= 24 else { print("not enough VRAM"); return }
print("ok with \(v) GB")
}
check(vram: 32)Functions and closures
Parameters have argument labels that make calls read like sentences. Closures are inline functions passed to map, filter and sorted.
func params(layers: Int, width: Int = 4096) -> Int {
12 * layers * width * width
}
print(params(layers: 32))
let squares = (1...5).map { $0 * $0 }
let sorted = ["H200", "B200", "H100"].sorted()
print(squares, sorted)Structs, enums and protocols
Structs are value types and the default choice for data. Enums can carry values. Protocols define behaviour that types adopt.
protocol Describable { var summary: String { get } }
enum Precision { case fp32, fp16, fp8 }
struct Gpu: Describable {
let name: String
let vramGb: Int
var summary: String { "\(name): \(vramGb) GB" }
}
let gpus = [Gpu(name: "H100", vramGb: 80), Gpu(name: "B200", vramGb: 180)]
print(gpus.filter { $0.vramGb > 100 }.map(\.summary), Precision.fp8)async/await and errors
Functions that can fail are marked throws and called with try. Asynchronous work uses async/await, for example with URLSession.
import Foundation
func modelNames() async throws -> String {
let url = URL(string: "http://localhost:11434/api/tags")!
let (data, _) = try await URLSession.shared.data(from: url)
return String(decoding: data, as: UTF8.self)
}
do {
print(try await modelNames().prefix(120))
} catch {
print("Is Ollama running? \(error)")
}AI with Swift
Swift is the way to bring AI into Apple apps. Core ML runs converted models with the Neural Engine, MLX Swift runs and fine-tunes LLMs on Apple silicon, and Apple's Foundation Models framework gives apps access to the on-device Apple Intelligence model.
The essential libraries
Gradient descent from scratch
Learn y = 3x + 0.5 with loops.
let n = 100
let xs = (0..<n).map { -1 + 2 * Double($0) / Double(n - 1) }
let ys = xs.map { 3 * $0 + 0.5 + Double.random(in: -0.05...0.05) }
var w = 0.0, b = 0.0
let lr = 0.1
for _ in 0..<500 {
var gw = 0.0, gb = 0.0
for i in 0..<n {
let err = w * xs[i] + b - ys[i]
gw += 2 * err * xs[i] / Double(n); gb += 2 * err / Double(n)
}
w -= lr * gw; b -= lr * gb
}
print(String(format: "w=%.2f b=%.2f", w, b))Build an AI agent in Swift
With URLSession and JSONSerialization you can run the tool-calling loop against a local model. On Apple devices, the Foundation Models framework offers built-in tool calling with the on-device model.
import Foundation
func getWeather(_ city: String) -> String { "It is 24°C and sunny in \(city)." }
let tools: [[String: Any]] = [["type": "function", "function": [
"name": "get_weather", "description": "Weather for a city",
"parameters": ["type": "object", "properties": ["city": ["type": "string"]], "required": ["city"]]]]]
var messages: [[String: Any]] = [["role": "user", "content": "Should I take an umbrella in Lahore today?"]]
for _ in 0..<5 {
var req = URLRequest(url: URL(string: "http://localhost:11434/v1/chat/completions")!)
req.httpMethod = "POST"
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try JSONSerialization.data(withJSONObject: ["model": "llama3.1", "messages": messages, "tools": tools])
let (data, _) = try await URLSession.shared.data(for: req)
let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
let msg = ((json["choices"] as! [[String: Any]])[0]["message"]) as! [String: Any]
messages.append(msg)
guard let calls = msg["tool_calls"] as? [[String: Any]], !calls.isEmpty else {
print(msg["content"] ?? ""); break
}
for call in calls {
let fn = call["function"] as! [String: Any]
let args = try JSONSerialization.jsonObject(with: Data((fn["arguments"] as! String).utf8)) as! [String: String]
messages.append(["role": "tool", "tool_call_id": call["id"] ?? "", "content": getWeather(args["city"] ?? "")])
}
}In a real app, model messages with Codable structs instead of dictionaries.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Swift learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Swift cheat sheet
| Task | Syntax |
|---|---|
| Constant | let x = 1 |
| Optional | var s: String? = nil |
| Unwrap | if let v = s { } |
| Interpolate | "Hi \(name)" |
| Closure | arr.map { $0 * 2 } |
| Async | let d = try await f() |
Common mistakes
- Force-unwrapping with
!crashes on nil; unwrap safely. - Updating UI off the main actor causes warnings and bugs; mark UI code
@MainActor. - Structs are copied: changing a copy does not change the original.
Where to go next
- The Swift Programming Language — official book
- Hacking with Swift — free tutorials
- MLX Swift — LLMs on Apple silicon
On TensorCore.si: Kotlin volume, What is an NPU?.
Keyboard: [ previous language · ] next language · / search the library