Environment setup
Same as lesson 01: Xcode 27 with the Metal Toolchain, an iOS 27 target that links CoreAI.framework, a real device, and the coreai-models checkout with uv sync (Python 3.11+, PyTorch on MPS or CPU).
Check the cache, then decide what to show
AIModelCache.default.model(for:options:) returns a model when a specialization for that URL and options is already cached, and nil otherwise. It never specializes. Use it to decide if the user should see a "Preparing" state. This is the pattern from Apple's Managing model specialization and caching:
import CoreAI
@MainActor
final class ModelPreparer: ObservableObject {
@Published var preparing = false
func load(_ url: URL) async throws -> AIModel {
if let cached = try AIModelCache.default.model(for: url, options: .default) {
return cached
}
preparing = true
defer { preparing = false }
return try await AIModel(contentsOf: url, options: .default)
}
}
Specialize at a calm moment
AIModel.specialize(contentsOf:options:cache:cachePolicy:) runs specialization and stores the result, without you needing to run inference. Call it right after a model download finishes, or when the user turns on the AI feature, not when they press Send. Apple notes that calling it again with the same URL and options returns the cached result.
import CoreAI
func prepareAfterDownload(_ url: URL) async {
do {
try await AIModel.specialize(contentsOf: url, options: .default, cachePolicy: .persistent)
} catch {
print("specialize failed:", error)
}
}
Use the same SpecializationOptions here and at load time. The cache key is the model URL plus the options. If you specialize with .default and load with .cpuOnly, you pay again.
Keep the cache
- The system can delete specialized assets to free storage.
.persistentasks it to keep them (not available on tvOS). - An OS update can invalidate cached assets. Plan for one slow launch after updates.
- If you want to delete the source
.aimodelto save space, savemodel.bookmarkDataand load later withAIModel(resolvingBookmark:). If that returnsnil, download and specialize again. - Apps and extensions in one app group can share specializations with
AIModelCache(appGroup:).
Move the heavy part to build time
Apple's ahead-of-time guide describes coreai-build. It moves model compilation, the most expensive part of specialization, to your Mac. The output is one .aimodelc per device architecture.
xcrun coreai-build compile MyModel.aimodel \
--platform iOS --min-deployment-version 27.0 --output compiled/
ls compiled/ # MyModel.<arch>.aimodelc, one per architecture
xcrun coreai-build compile --help # see --preferred-compute and other options
Each device needs only its own file. Apple suggests hosting them and downloading the match, for example with the Background Assets framework. At runtime, pick the file with AIModel.deviceArchitectureName:
import CoreAI
func compiledAssetName(base: String) -> String {
"\(base).\(AIModel.deviceArchitectureName).aimodelc"
}
func loadCompiled(base: String, from folder: URL, fallbackSource: URL) async throws -> AIModel {
let compiled = folder.appendingPathComponent(compiledAssetName(base: base))
if FileManager.default.fileExists(atPath: compiled.path) {
return try await AIModel(contentsOf: compiled, options: .default)
}
// No match for this architecture (or not downloaded yet): use the portable model.
return try await AIModel(contentsOf: fallbackSource, options: .default)
}
Two limits from Apple's page: ahead-of-time compilation only covers devices that support Apple Intelligence, and the compiled file still needs some on-device specialization. It is faster, not zero. Keep the cache check from above even with .aimodelc files.
What we could not verify
We looked for Apple documentation on how specialization behaves on chips with more than one Neural Engine (for example, extra cold-load time per Neural Engine). We did not find any on developer.apple.com or in apple/coreai-models. Measure cold load on each device class you ship, with the timers from lesson 01, instead of assuming.
Sources
- Apple: Managing model specialization and caching
- Apple: Compiling Core AI models ahead of time
- Apple: AIModelCache
Key concepts
AIModelCache.default.model(for:options:)tells you if a specialization is cached and never specializes.AIModel.specialize(...)specializes without inference. Run it after download or on feature enable.- The cache key is the model URL plus SpecializationOptions. OS updates and storage pressure can remove entries.
coreai-build compilemakes one.aimodelcper architecture. Pick it withAIModel.deviceArchitectureName.
Takeaways
- Show a Preparing state only on a cache miss.
- Specialize before the user presses Send, with the same options you load with.
- Ship per-architecture .aimodelc files for Apple Intelligence devices and keep the portable model as a fallback.