ios - 如何在今天的小部件扩展中使用核心数据?

标签 ios swift xcode core-data

我想在今天的扩展中使用核心数据。 我在下面尝试了一些方法。

  1. 创建应用组并定位到应用和今日扩展!

  2. this link 之后创建 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 的问题吗?

最佳答案

您不必子类化 NSPersistentContainer 即可设置自定义存储目录。

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 ...

}

使用您的 App Group 目录实例化它:

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)

关于ios - 如何在今天的小部件扩展中使用核心数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42360879/

相关文章:

Ios 分组条形图,不绘制零值或空值

ios - AVPlayer,如何保存当前录制时间

swift - Alamofire:网络错误与无效状态代码?

objective-c - xcode中项目/目标的单独设置是什么意思?

ios - UIPercentDrivenInteractiveTransition 未完成动画

ios - 如何降级或安装旧版本的 Cocoapods

ios - 从 View Controller 访问界面构建器对象

ios - 如何从 View 获取数据到 UITabBarController

ios - 适用于 iOS 的自定义 ionic/cordova 插件。插件错误中未定义方法

ios - 如何为 UITableView 设置自动高度?