如何在小部件今日扩展中使用Core数据?

问题描述:

我想在今天的扩展中使用核心数据。 我尝试了下面的一些方法。如何在小部件今日扩展中使用Core数据?

  1. 创建应用程序组和目标应用程序和今天扩展!

  2. 创建以下this link

  3. CoreDataStack类

完整的代码是在这里:

final class CoreDataStack { 
static let sharedStack = CoreDataStack() 
var errorHandler: (Error) -> Void = {_ in } 
//#1 
lazy var persistentContainer: NSPersistentContainer = { 
    let container = NSPersistentContainer(name: "spark") 
    container.loadPersistentStores(completionHandler: { [weak self](storeDescription, error) in 
     if let error = error { 
      NSLog("CoreData error \(error), \(error._userInfo)") 
      self?.errorHandler(error) 
     } 
    }) 
    return container 
}() 

//#2 
lazy var viewContext: NSManagedObjectContext = { 
    return self.persistentContainer.viewContext 
}() 

//#3 
// Optional 
lazy var backgroundContext: NSManagedObjectContext = { 
    return self.persistentContainer.newBackgroundContext() 
}() 

//#4 
func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
    self.viewContext.perform { 
     block(self.viewContext) 
    } 
} 

//#5 
func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) { 
    self.persistentContainer.performBackgroundTask(block) 
} 



private init() { 
    //#1 
    NotificationCenter.default.addObserver(self, 
              selector: #selector(mainContextChanged(notification:)), 
              name: .NSManagedObjectContextDidSave, 
              object: self.managedObjectContext) 

    NotificationCenter.default.addObserver(self, 
              selector: #selector(bgContextChanged(notification:)), 
              name: .NSManagedObjectContextDidSave, 
              object: self.backgroundManagedObjectContext) 
} 

deinit { 
    NotificationCenter.default.removeObserver(self) 
} 

//#2 
lazy var libraryDirectory: NSURL = { 
    let urls = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask) 
    return urls[urls.count-1] as NSURL 
}() 

//#3 
lazy var managedObjectModel: NSManagedObjectModel = { 
    let modelURL = Bundle.main.url(forResource: "spark", withExtension: "momd")! 
    return NSManagedObjectModel(contentsOf: modelURL)! 
}() 

//#4 
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { 
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: 
     self.managedObjectModel) 
    let url = self.libraryDirectory.appendingPathComponent("spark.sqlite") 
    do { 
     try coordinator.addPersistentStore(ofType: 
      NSSQLiteStoreType, 
              configurationName: nil, 
              at: url, 
              options: [ 
              NSMigratePersistentStoresAutomaticallyOption: true, 
              NSInferMappingModelAutomaticallyOption: true 
      ] 
     ) 
    } catch { 
     // Report any error we got. 
     NSLog("CoreData error \(error), \(error._userInfo)") 
     self.errorHandler(error) 
    } 
    return coordinator 
}() 

//#5 
lazy var backgroundManagedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
    privateManagedObjectContext.persistentStoreCoordinator = coordinator 
    return privateManagedObjectContext 
}() 

//#6 
lazy var managedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var mainManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) 
    mainManagedObjectContext.persistentStoreCoordinator = coordinator 
    return mainManagedObjectContext 
}() 

//#7 
@objc func mainContextChanged(notification: NSNotification) { 
    backgroundManagedObjectContext.perform { [unowned self] in 
     self.backgroundManagedObjectContext.mergeChanges(fromContextDidSave: notification as Notification) 
    } 
} 
@objc func bgContextChanged(notification: NSNotification) { 
    managedObjectContext.perform{ [unowned self] in 
     self.managedObjectContext.mergeChanges(fromContextDidSave: notification as Notification) 
    } 
} 
} 
struct CoreDataServiceConsts { 
static let applicationGroupIdentifier = "group.zz.zz.zz"//example 
} 

final class PersistentContainer: NSPersistentContainer { 
    internal override class func defaultDirectoryURL() -> URL { 
     var url = super.defaultDirectoryURL() 
     if let newURL = 
      FileManager.default.containerURL(
       forSecurityApplicationGroupIdentifier: CoreDataServiceConsts.applicationGroupIdentifier) { 
      url = newURL 
     } 
     return url 
    } 

我能在今天的扩展使用核心数据!但是,实体是空的。 而且我测试的代码都很好。没有错误(因为我保存了一些测试数据,所以我完全可以工作。) 我真的不知道这个问题。 它是关于xcode的问题吗?

+0

您是否在两个目标中都包含Core Data类? (应用程序和扩展名) – Adolfo

+0

@Adolfo yup!我可以在xcdatamodeld文件中看到同时检查应用程序和扩展程序 –

您无需子类NSPersistentContainer即可设置自定义商店目录。

guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupId) else { 
     fatalError("could not get shared app group directory.") 
    } 

let modelName = "Model" 
let storeName = "store" 

let myStore = CoreDataStack(withManagedObjectModelName: modelName, sqliteStoreName: storeName, storeBaseUrl: groupURL) 
+0

谢谢您的回答!什么是商店名称?我怎么找到它? –

+0

您将其命名(作为常量)。它以实际的sqlite文件名“myStoreName.sqlite”结束。 – shallowThought

+0

哦!我懂了。然后如何在今天的扩展类中调用上下文? –

尝试创建一个新的“可可触摸框架”,把你的xcdatamodeld文件和自定义管理对象类的出现,让您可以在之间共享:使用您的应用程序组目录它

class CoreDataStack { 
    public private(set) var persistentContainer: NSPersistentContainer 

    public init(withManagedObjectModelName momdName:String, sqliteStoreName storeName:String, storeBaseUrl baseUrl:URL?) { 
     guard let modelURL = Bundle(for: type(of: self)).url(forResource: momdName, withExtension:"momd") else { 
      fatalError("Error loading model from bundle") 
     } 

     guard let mom = NSManagedObjectModel(contentsOf: modelURL) else { 
      fatalError("Error initializing mom from: \(modelURL)") 
     } 

     persistentContainer = NSPersistentContainer(name: momdName, managedObjectModel: mom) 

     // If a base URL is given, use it. Else use persistent stores default 
     if let baseUrl = baseUrl { 
      var storeUrl = baseUrl.appendingPathComponent(momdName) 
      storeUrl = storeUrl.appendingPathExtension("sqlite") 
      let description = NSPersistentStoreDescription(url: storeUrl) 
      persistentContainer.persistentStoreDescriptions = [description] 
     } 

     persistentContainer.loadPersistentStores() { (storeDescription, error) in 
      if let error = error { 
        fatalError("Unresolved error \(error)") 
      } 
     } 
    } 

    // MARK: - ... save, get context and others ... 

} 

实例化应用程序和扩展。

然后子类NSPersistentContainer。

class SparkPersistentContainer: NSPersistentContainer = { 
    override class func defaultDirectoryURL() -> URL { 
    return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.your-app")! 

    init() { 
     let modelURL = Bundle(for: CustomManagedObject.self).url(forResource: "Spark", withExtension: "momd")! 
     let model = NSManagedObjectModel(contentsOf: modelURL)! 
     super.init(name: "Spark", managedObjectModel: model) 
    } 
}