从 Today Extension 保存到 Core Data 时,只能从 Widget 访问数据 - 而不是从主应用程序

When saving to CoreData from Today Extension, Data only accesable from Widget - NOT from Main Application

我正在为 iOS 和 Swift 编写一个应用程序 3.

在我的主 iOS 应用程序中,我使用 NSFetchedResultsController 将保存的项目显示为 TableView。 可以(当然)从另一个 ViewController 添加新项目。 -> 这一切都非常棒。

所以我认为,如果我可以从 TodayWidget 中非常快速地添加一个新项目,那就太好了。

我做了什么:

  1. 创建了一个 SharedCode Framework 并将 AppGroup 添加到我的主应用程序和 Today Widget。

  2. 移动了我的CoreDataStack.swiftClass、.xcdatamodeled和我的Item+CoreDataClass.swiftItem+CoreDataProperties.swift 文件到我的 SharedCode 框架。

  3. 为我的 appGroupID

  4. 将 NSPersistentContainer 转入 addforSecurityApplicationGroupIdentifier
  5. 在我的 ViewController 中重写了我的 CoreData 代码以使用创建的 CoreDataStack.shared.managedContext

  6. 测试中。惊人的。我的 NSFetchedResultsController 正在工作,并且添加新项目按预期工作。好的。 -> 继续前进。

  7. 在我的 Today Widget 中,我使用一个简单的 NSFetchRequest 从 CoreData 获取最后输入的项目。完美运行!

  8. 添加了用于修改数据并将其保存到 CoreData 的按钮。在这里我也使用 CoreDataStack.shared.managedContextCoreDataStack.shared.save()

  9. 自动重新加载我的数据 AND?! 太棒了。一切都很好。数据已保存,新数据显示在 Today Extension 中。此外,当我计算 NSFetchRequest 的结果时,项目的数量会增加。

现在解决我的问题:

我通过扩展程序添加的所有数据都没有显示在我的 iOS 主应用程序中。 当我从 CoreData 中获取项目时,只有那些显示我在主应用程序中创建的项目。 -.-

我不知道出了什么问题。 就像我有两个不同的 CoreDataStores。 此外,在我通过小部件添加了一个项目之后 - 小部件不会从主应用程序中获取一个项目。只有最后一个从 Widget 输入。

- 这是我的代码:

CoreDataStack.swift

public class CoreDataStack {

    public static let shared = CoreDataStack()
    public var errorHandler: (Error) -> Void = {_ in }

    //#1
    lazy var persistentContainer: PersistentContainer = {

        let container = PersistentContainer(name: ServiceConsts.modelName)
        var persistentStoreDescriptions: NSPersistentStoreDescription

        let storeUrl =  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: ServiceConsts.appGroupID)!.appendingPathComponent("\(ServiceConsts.modelName).sqlite")

        let description = NSPersistentStoreDescription()
        description.shouldInferMappingModelAutomatically = true
        description.shouldMigrateStoreAutomatically = true
        description.url = storeUrl

        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url:  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: ServiceConsts.appGroupID)!.appendingPathComponent("\(ServiceConsts.modelName).sqlite"))]

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container 
    }()

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

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

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

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

    //#6
    public func saveContext () {
        guard managedContext.hasChanges else { return }
        do {
            try managedContext.save()
        } catch let error as NSError {
            print("Unresolved error \(error), \(error.userInfo)")
        }
    }
}

PersistentContainer.swift

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

有人可以帮忙吗? 我真的不知道我做错了什么。

如果有人能给我提示,那就太棒了:)

谢谢 <3

我终于解决了我的问题 <3。

原来如此简单。

经过数小时的测试测试哭泣并砍掉我的 MacBook ;) 我发现了让我丧命的东西。

我测试了主应用程序中的简单获取请求是否会从 Today Extension 中获取添加的项目。那是有效的。

而且比我看到的还要多。在我的主应用程序中。 NSFetchedResultController。我使用了 缓存

现在,当通过小部件添加新权重时,我会通知主应用程序 - 然后调用我的刷新函数。

func handleRefresh(_ refreshControl: UIRefreshControl) {

    NSFetchedResultsController<NSFetchRequestResult>.deleteCache(withName: "weightCache")

    do {
        try fetchedResultsController.performFetch()
        setupView()
        self.tableView.reloadData()
    } catch let error as NSError {
        print("Fetching error: \(error), \(error.userInfo)")
    }

    refreshControl.endRefreshing()
}

就这么简单。

删除缓存即可