Compilation
Essence
Compilation is translating high-level source code into machine code for the target CPU before launch (ahead-of-time). On iOS this is the only way: third-party apps may not generate code at run time (JIT), so Swift and Objective-C are compiled fully.
The swiftc pipeline
- Parse — text → AST (syntax tree). Syntax errors are caught here.
- Sema — type checking and inference, overload resolution. The most expensive stage: long expressions with literals can take seconds.
- SILGen → SIL — Swift Intermediate Language: this is where definite initialisation checks, ARC
retain/release, exclusivity enforcement and Swift-level optimisations (devirtualisation, generic specialisation, inlining) live. - IRGen → LLVM IR — a machine-independent representation; LLVM optimises and emits code for arm64 (device) or arm64/x86_64 (simulator).
- Linker (
ld) — object files and libraries are merged into an executable; dynamic frameworks are loaded bydyldat launch.
swiftc -emit-sil main.swift # inspect the SIL
swiftc -emit-ir main.swift # LLVM IR
swiftc -O -wmo main.swift # optimised, whole module
What gets asked in practice
- Debug vs Release:
-Onone(fast builds, precise debugging) versus-O/-Osize;-wmo(whole-module optimisation) lets the compiler see the entire module and remove dynamic dispatch. finalandprivatehelp the compiler: it knows the method cannot be overridden and calls it directly.- Incremental builds and modularisation (SPM packages) are the main way to cut build times.
- Bitcode is no longer accepted for iOS (since Xcode 14); App Thinning and arm64 Mach-O binaries are what actually ships to the App Store.
- The compiler also enforces Swift 6 strict concurrency: data races become compile errors rather than production crashes.
What the interviewer looks for
Do you understand that type checking, ARC and concurrency checks are the compiler's job, not the runtime's, and how build settings (-O, -wmo, final) affect the app's performance.