This article is useful because it solves one very specific gap between normal app code and extension code.
In a regular iOS target, Core Data is often treated as an app-owned singleton that
lives behind the AppDelegate or a persistence controller. That works as
long as only the main app target needs the store. The moment an iMessage extension,
Today extension, Siri extension, or another app extension needs the same data, the
default file location stops being enough.
The article does not try to redesign Core Data architecture from scratch. It takes a
smaller path: move the SQLite store into an App Group container, then
create a custom persistent container class that points Core Data to that shared
directory.
The article starts from the normal app-only pattern: grab the persistent container from the app delegate and use its viewContext.
The baseline code is simple and familiar:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
The point of the article is not that this code is wrong. It is that it assumes the database lives where the main app expects it to live. If an extension target also needs to open the store, you first need a file location that both the app and the extensions are entitled to read.
Turn on App Group for the main app and every extension target, then assign the same group identifier everywhere.
The first project-level step stays in Xcode's
Signing & Capabilities area. Add the
App Group capability to the main app and to each extension target that
should see the same database. Then choose the same group identifier for all of them.
App Group capability from the target capabilities screen.
Create a custom persistent container that overrides the default directory and points the SQLite file into the shared group container.
The central trick in the article is the custom container subclass. Instead of letting
Core Data use its usual target-specific default location, override
defaultDirectoryURL() and build the path from the App Group container
URL plus the SQLite filename.
The article also calls out one practical detail: look up the .xcdatamodel
name first. If your model is named Sakura.xcdatamodel, the Core Data
stack name should be Sakura.
import Foundation
import CoreData
class NSCustomPersistentContainer: NSPersistentCloudKitContainer {
override open class func defaultDirectoryURL() -> URL {
var storeURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.[App Group Name]"
)
storeURL = storeURL?.appendingPathComponent("Sakura.sqlite")
return storeURL!
}
}
Once the container class points to the shared directory, the rest of the Core Data access pattern looks familiar again.
The access code in this article is intentionally close to the regular app-only version. The difference is that the persistent container instance now uses the custom subclass, so loading the store resolves into the shared App Group path instead of the target's normal default directory.
lazy var persistentContainer: NSPersistentContainer = {
let container = NSCustomPersistentContainer(name: "Sakura")
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
print(error.localizedDescription)
}
}
return container
}()
let context = persistentContainer.viewContext
That is the main value of the technique: after the storage location is corrected, the rest of the app and extension code can continue to interact with a standard Core Data context instead of learning a completely different persistence API.
The article is explicit about timing: make this storage-layout decision before shipping, not as a casual update to an app that already has user data.
This article contains two warnings that are worth preserving. First, it says to make this change during the first development stage of an unpublished app instead of casually introducing it later to an already-shipped product. Second, if user data already exists, take a separate backup before making important storage changes.
That caution is the right closing note. Moving the persistent store path is powerful, but it is also a real storage migration decision. The setup itself is small; the consequences of getting it wrong are not.