【问题标题】:CollectionView - Drop pdf file onto collectionView (loadObject(ofClass:) not working properly)CollectionView - 将 pdf 文件拖放到 collectionView 上(loadObject(ofClass:) 无法正常工作)
【发布时间】:2018-11-30 18:36:10
【问题描述】:

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

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 文件,这会在保存上下文时导致合并错误(因为后台任务为每个删除的文件同时运行)。

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

【问题讨论】:

  • 我知道这是旧的......但你最终做了什么?我也有同样的问题,很奇怪。
  • 所以,我已经很久没有遇到这个问题了。我想我确实找到了方法。我要发布一个答案。也许它有帮助:D

标签: ios swift uicollectionview drag-and-drop


【解决方案1】:

很久没看代码了,希望对你有帮助:

我的解决方案是使用方法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
            }
        }
        // ...
    }    
}

请注意:我最终不需要保存到数据库中,但这样一来,它应该不是问题(希望如此)。

【讨论】:

  • 谢谢,我试试看!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-04
  • 2022-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 2013-05-28
相关资源
最近更新 更多