iOS расширение сегодня с основными данными - PullRequest
3 голосов
/ 01 марта 2020

Я пытаюсь сделать сегодняшнее расширение для моего ios приложения. Это расширение сегодня будет отображать «следующий» курс на основе данных, сохраненных с основными данными. Я провел некоторое исследование и понимаю, что должен поделиться своим persistentContainer с группой приложений. Итак, я сделал:

  • включил группы приложений как для ios приложений, так и для сегодняшних целей расширения.
  • закодировал функцию, чтобы поделиться ей:
public extension NSPersistentContainer {
    func addToAppGroup(id: String) {
        guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: id) else {
            fatalError("Shared file container could not be created.")
        }
        let storeURL = fileContainer.appendingPathComponent("\(self.name).sqlite")
        let storeDescription = NSPersistentStoreDescription(url: storeURL)
        self.persistentStoreDescriptions.append(storeDescription)
    }
}

затем в моем основном стеке данных:

internal class CoreDataContainer {

    static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentCloudKitContainer(name: "SchoolCompanion")
        container.addToAppGroup(id: "group.com.Ce-dricLoneux.School-Companion")
        container.loadPersistentStores(completionHandler: { (_, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = CoreDataContainer.persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

, что файлы и xcdatamodel совместно используются обеими целями. В этот момент я думал, что смогу получить доступ к своим основным данным из моего расширения, но когда я делаю запрос на выборку, я не получаю никакого результата. ControllerDidChangeContent никогда не выполняется.

class TodayViewController: UIViewController, NCWidgetProviding {
private func configureFetchedResultsController() {
        let request: NSFetchRequest<Course> = Course.fetchRequest()
        request.sortDescriptors =  []
        self.fetchedResultsController = NSFetchedResultsController<Course>(fetchRequest: request, managedObjectContext: CoreDataContainer.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
        self.fetchedResultsController.delegate = self
        do {
            try self.fetchedResultsController.performFetch()
        } catch {
            print(error.localizedDescription)
        }
    }

override func viewDidLoad() {
        super.viewDidLoad()

        self.extensionContext?.widgetLargestAvailableDisplayMode = .compact
        self.configureFetchedResultsController()

    }

func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
        // Perform any setup necessary in order to update the view.

        // If an error is encountered, use NCUpdateResult.Failed
        // If there's no update required, use NCUpdateResult.NoData
        // If there's an update, use NCUpdateResult.NewData

        completionHandler(NCUpdateResult.newData)
    }
}

// MARK: - FetchedResultsController Delegate

extension TodayViewController: NSFetchedResultsControllerDelegate {
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        print("content did change")
    }
}

Я также пытался создать запрос на выборку, но в результате я получил пустой массив. Почему я не получаю никакого результата?

Еще одна вещь: я использовал контроллер nsfetchedResult, чтобы обновлять sh данные просмотра каждый раз, когда данные обновляются из приложения ios, так что это нормально, или я должен использовать метод widgetPerformUpdate? В этом случае мы не знаем, когда будет обновлено сегодняшнее расширение, и оно может отображать устаревшие данные.

Основная используемая документация: https://www.avanderlee.com/swift/core-data-app-extension-data-sharing/

Ответы [ 2 ]

1 голос
/ 02 марта 2020

URL для вашей группы приложений находится здесь:

let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "SchoolCompanion)

Файл sqlite находится здесь. Вам не нужен контейнер Cloud.

0 голосов
/ 13 марта 2020

Вы должны создать подкласс NSPersistentCloudKitContainer, как показано ниже, возвращая URL-адрес группы приложений для defaultDirectoryURL(). Затем в CoreDataStack используйте let container = GroupedPersistentCloudKitContainer(name: "SchoolCompanion"). Также удалите ваш звонок на addToAppGroup(...). Вам нужно будет создать экземпляр GroupedPersistentCloudKitContainer как в приложении, так и в расширении, а также убедиться, что GroupedPersistentCloudKitContainer связан с обеими целями.

class GroupedPersistentCloudKitContainer: NSPersistentCloudKitContainer {

    enum URLStrings: String {
        case group = "group.com.yourCompany.yourApp"
    }


    override class func defaultDirectoryURL() -> URL {
        let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: URLStrings.group.rawValue)

        if !FileManager.default.fileExists(atPath: url!.path) {
            try? FileManager.default.createDirectory(at: url!, withIntermediateDirectories: true, attributes: nil)
        }
        return url!
    }
    ...
}
...