Cra sh возникает при двойном запуске Share Extension в системных файлах для передачи файла приложению - PullRequest
5 голосов
/ 12 июля 2020

Приложение использует расширение Share Extension для импорта строки файлов .txt в Core Data. А затем синхронизирует основные данные с iCloud. Есть сущность под названием Item. При совместном использовании нового элемента в системных файлах через расширение общего доступа код должен вычислить order для нового элемента, который будет импортирован. И код:

import Foundation
import CoreData

@objc(Item)
public class Item: NSManagedObject, Identifiable {

    class func nextOrder() -> Int {

        let keyPathExpression = NSExpression.init(forKeyPath: "order")
        let maxNumberExpression = NSExpression.init(forFunction: "max:", arguments: [keyPathExpression])

        let expressionDescription = NSExpressionDescription()
        expressionDescription.name = "maxNumber"
        expressionDescription.expression = maxNumberExpression
        expressionDescription.expressionResultType = .decimalAttributeType

        var expressionDescriptions = [AnyObject]()
        expressionDescriptions.append(expressionDescription)

        // Build out our fetch request the usual way
        let request: NSFetchRequest<NSFetchRequestResult> = Item.fetchRequest()
        request.resultType = .dictionaryResultType
        request.propertiesToFetch = expressionDescriptions
        request.predicate = nil

        // Our result should to be an array of dictionaries.
        var results: [[String:AnyObject]]?

        do {
            results = try CoreData.stack.context.fetch(request) as? [[String:NSNumber]]   <-- errors here, Exception: "executeFetchRequest:error: <null> is not a valid NSFetchRequest."

            if let maxNumber = results?.first!["maxNumber"]  {
                // Return one more than the current max order
                return maxNumber.intValue + 1
            } else {
                // If no items present, return 0
                return 0
            }
        } catch _ {
            // If any failure, just return default
            return 0
        }
    }
}

Код расширения общего доступа:

import UIKit
import Social
import CoreServices
import CoreData

class ShareViewController: SLComposeServiceViewController {

    var item = [Item]()
    var newItem: Item?

    override func isContentValid() -> Bool {

        return true
    }


    override func didSelectPost() {

        // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.

        if let inputItem = extensionContext!.inputItems.first as? NSExtensionItem {

            if let itemProvider = inputItem.attachments?.first {

                // This line was missing
                if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
                    itemProvider.loadItem(forTypeIdentifier: kUTTypeText as String) { (urlItem, error) in

                        if let filePathURL = urlItem as? URL {

                            do {
                                let nextOrder = Item.nextOrder()  <-- errors here, Exception: "executeFetchRequest:error: <null> is not a valid NSFetchRequest."

                                // Some operation to import new item
                                // useless code for this question
                                // ...

                            } catch {
                                print("error")
                            }
                        }

                    }
                }
            }
        }

        self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
    }


    lazy var persistentContainer: NSPersistentCloudKitContainer = {

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

        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

        return container
    }()

    // MARK: - Core Data Saving support
    func saveContext () {
        let context = persistentContainer.viewContext

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

}

Расширение общего доступа хорошо работает при первом совместном использовании. После обмена в основные данные добавляется новый элемент.

Но он будет треснуть sh при обмене файлами во второй раз, говоря: Exception: "executeFetchRequest:error: <null> is not a valid NSFetchRequest."

Ошибка кода находится в func nextOrder(), а строка - results = try CoreData.stack.context.fetch(request) as? [[String:NSNumber]], которая была прокомментирована в приведенном выше коде.

Аналогичный вопрос здесь . Но мой баг такой же? И я не решил его, следуя ответам в вопросе.

...