Thank you again for the clarification.
Based on your recommendation for iOS 17–18, I implemented the migration as a one-time file-system move before creating the ModelContainer.
I also took your suggestion of placing the database inside its own folder within the App Group, so the migration simply moves the entire persistence package into that directory before SwiftData is initialized.
In case it's useful to anyone else who comes across this thread, here's the implementation I've ended up with:
let modelContainer: ModelContainer = {
let schema = Schema([
MyModel.self
])
let fileManager = FileManager.default
let storePrefix = "Store"
let storeName = "\(storePrefix).sqlite"
let appGroupID = "group.com.example.myapp"
let applicationSupportDirectory = fileManager.urls(for: .applicationSupportDirectory,
in: .userDomainMask)[0]
let oldStoreURL = applicationSupportDirectory.appendingPathComponent(storeName)
guard let appGroupURL = fileManager.containerURL(
forSecurityApplicationGroupIdentifier: appGroupID
) else {
fatalError("App Group not found.")
}
// Store everything in a dedicated folder so future migrations only need
// to move this directory.
let persistenceFolderURL = appGroupURL.appendingPathComponent("Persistence", isDirectory: true)
let newStoreURL = persistenceFolderURL.appendingPathComponent(storeName)
if !fileManager.fileExists(atPath: persistenceFolderURL.path) {
try! fileManager.createDirectory(at: persistenceFolderURL,
withIntermediateDirectories: true)
}
// One-time migration from Application Support to the App Group.
if fileManager.fileExists(atPath: oldStoreURL.path) &&
!fileManager.fileExists(atPath: newStoreURL.path) {
let contents = try! fileManager.contentsOfDirectory(
at: applicationSupportDirectory,
includingPropertiesForKeys: nil,
options: [] // Don't skip hidden folders such as .Store_SUPPORT
)
for fileURL in contents {
let fileName = fileURL.lastPathComponent
let shouldMove =
fileName == storeName ||
fileName == "\(storeName)-wal" ||
fileName == "\(storeName)-shm" ||
fileName == ".\(storePrefix)_SUPPORT" ||
fileName == "\(storePrefix)_ckAssets"
if shouldMove {
let destinationURL = persistenceFolderURL.appendingPathComponent(fileName)
try! fileManager.moveItem(at: fileURL, to: destinationURL)
}
}
}
let configuration = ModelConfiguration(url: newStoreURL)
return try! ModelContainer(for: schema, configurations: configuration)
}()
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags: