I'm developing a library for iOS using Swift 5, and I want this library to use CoreData independent of the application which consumes that library and this is what I've done so far:
- Created the entities with their respective data types
- Created the
.xcdatamodeld
file, which contains the entities - Created a
CoreDataManager
which looks like this:
// MARK: - CoreDataManager
final class CoreDataManager {
static let shared = CoreDataManager()
private static let defaultObject = NSManagedObject.init()
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Audit")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
}
And the trouble is I'm trying to get the context by:
let coreDataManager = CoreDataManager.shared
let context = coreDataManager.persistentContainer.viewContext
and context
is returning nil
please help
CodePudding user response:
I solved it, and apparently the trouble was that the ios application where I wanted to use my library wasn't finding the .xcdatamodeld
file which resulted in a useless NSPersistentContainer
object, which also meant that let context = persistentContainer.viewContext
was nil
.
In order to avoid this kind of troubles in the future, I'll left a list of important considerations when working with CoreData and swift libraries.
Key things to consider
- Make sure the app that is consuming your library knows exactly where
to look for it. Might want to take a look at
- Make sure your model file name matches the
NSPersistentContainer
name. - (NOT SURE ABOUT THIS) I changed the class definition of my NSManagedObjects from
class Audit: NSManagedObject {}
to
public class Audit: NSManagedObject {}
And even when I'm not sure if that makes sense, It could work for you.
Finally I'll leave the code that worked for me
// MARK: - CoreDataManager final class CoreDataManager { static let shared = CoreDataManager() private static let defaultObject = NSManagedObject.init() lazy var persistentContainer: NSPersistentContainer? = { let modelURL = Bundle(for: Audit.self).url(forResource: "Audit", withExtension: "momd") guard let model = modelURL.flatMap(NSManagedObjectModel.init) else { print("Fail to load the trigger model!") return nil } let container = NSPersistentContainer(name: "Audit", managedObjectModel: model) container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() }
And to get the context outside
let coreDataManager = CoreDataManager.shared guard let context = coreDataManager.persistentContainer?.viewContext else { print("Nil context case") return }
Hope you guys find it helpful!!
CodePudding user response:
You can try defining this scope in your AppDelegate:
lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Audit") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }()
And then use it in your CoreDataManager file like this:
class CoreDataManager: NSObject { static let shared = CoreDataManager() let managedContext = _appDelegator.persistentContainer.viewContext //Here _appDelegator is the object to your AppDelegate class }
- Make sure your model file name matches the