CollectionView-将pdf文件拖放到collectionView上(loadObject(ofClass :)无法正常工作)

时间:2018-11-30 18:36:10

标签: ios swift uicollectionview drag-and-drop

我在通过拖放会话(使用UICollectionView's Drag&Drop feature)加载pdf文件时遇到问题。

collectionView(_:performDropWith:coordinator)内,我想将放置的项目加载到后台线程中:

func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
    // I'm dropping a valid pdf file from the Files app in iOS.

    // I'm using performBackgroundTask because I want to save stuff to the database
    appDelegate.persistentContainer.performBackgroundTask({ (privateContext) in
        for item in coordinator.items {      

            // This correctly returns true      
            if item.dragItem.itemProvider.canLoadObject(ofClass: MyPDFDocument.self) {

                item.dragItem.itemProvider.loadObject(ofClass: MyPDFDocument.self) { (pdfItem, error) in
                   // This is not called
                }

            }
        }
     })

}

final class MyPDFDocument: PDFDocument, NSItemProviderReading {

    public static var readableTypeIdentifiersForItemProvider: [String] {
        return [kUTTypePDF as String]
    }

    public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> ComicBookPDFDocument {
        return MyPDFDocument(data: data)!
    }

}

但是,它不起作用。应该loadObject(ofClass:)调用块,而根本不调用它。在主线程上工作得很好。

问题是,我无法将performBackgroundTask块放在loadObject(ofClass:)内(然后放置的对象会完美加载),因为如果放置多个pdf文件,则在保存上下文时会导致合并错误(因为后台任务针对每个删除的文件同时运行。

有什么想法吗?是否不允许从另一个线程中加载对象?

1 个答案:

答案 0 :(得分:0)

查看代码已经很长时间了,但是我希望这会有所帮助:

对我来说,解决方案是使用方法loadObjects(ofClass:completion:)。这将异步获取所需文件的所有对象。 documentation中未说明。但是,如果您按cmd单击该方法并转到其声明,则会出现以下注释:

/* A convenience method that can be used only during the UIDropInteractionDelegate's
     * implementation of `-dropInteraction:performDrop:`.
     * Asynchronously instantiates objects of the provided class for each
     * drag item that can do so. The completion handler is called on the
     * main queue, with an array of all objects that were created, in the
     * same order as `items`.
     * The progress returned is an aggregate of the progress for all objects
     * that are loaded.
     */
    func loadObjects(ofClass aClass: NSItemProviderReading.Type, completion: @escaping ([NSItemProviderReading]) -> Void) -> Progress

实例化对象后,在主队列上调用完成处理程序。从这里,您可以调度到后台队列,并对文件进行任何操作。

我抓取了最终得到的代码并对其进行了简化:

// ValidComicBookFile is my NSItemProviderReading type that accepts multiple file types, like archive and pdf
coordinator.session.loadObjects(ofClass: ValidComicBookFile.self) { (importedObjects) in
    guard let validComicBookFiles = importedObjects as? [ValidComicBookFile] else {
        // Handle errors
    }

    DispatchQueue.global(qos: .userInitiated).async {
        // ...
        for (index, file) in validComicBookFiles.enumerated() {
            switch file.fileType {
            case .archive:
                // Unpack it and stuff
            case .pdf:
                // For example:
                if let pdfDoc = PDFDocument(data: file.data) {
                    pdfs.append(pdfDoc) // Append it to an array I created earlier
                }
            case .none:
                break
            }
        }
        // ...
    }    
}

一个注意事项:我最终并不需要保存到数据库,但是这样,(希望)这应该不是问题。