Ios 在UIActivityItemProvider中动态创建UIDocument

Ios 在UIActivityItemProvider中动态创建UIDocument,ios,semaphore,dispatch-async,uidocument,Ios,Semaphore,Dispatch Async,Uidocument,我使用核心数据来存储用户的数据。我想在UI中提供一个共享按钮,以便在用户希望的任何地方导出数据。我创建了一个符合UIActivityItemSource的类。如果它只是从activityViewController:itemForActivityType返回一个数据对象,但该文件具有系统提供的文件名,则会成功。因此,我现在尝试动态生成UIDocument,将其保存到文件系统,并将URL(UIDocument.fileURL)返回到活动视图控制器。问题是UIDocument.save是异步的,但在

我使用核心数据来存储用户的数据。我想在UI中提供一个共享按钮,以便在用户希望的任何地方导出数据。我创建了一个符合
UIActivityItemSource
的类。如果它只是从
activityViewController:itemForActivityType
返回一个数据对象,但该文件具有系统提供的文件名,则会成功。因此,我现在尝试动态生成
UIDocument
,将其保存到文件系统,并将
URL
UIDocument.fileURL
)返回到活动视图控制器。问题是
UIDocument.save
是异步的,但在保存文件之前,我无法从
activityViewController:itemForActivityType
返回。我的最新代码如下所示:

类init:

let saveQueue = DispatchQueue(label: "saveQueue")
let saveSemaphore = DispatchSemaphore(value: 0)

其行为是异步代码启动,但从未调用save的completion函数。我做错了什么


根据Casey的帮助,我的最终解决方案是覆盖
UIDocument.save

override func save(to url: URL, for saveOperation: UIDocument.SaveOperation, completionHandler: ((Bool) -> Void)? = nil) {
    do {
        let contents = try self.contents(forType: GlobalConst.exportType) as! Data
        try contents.write(to: url, options: [.atomicWrite])
        completionHandler?(true)
    } catch {
        print("write error: \(error)")
        completionHandler?(false)
    }
}

我还不明白为什么超类保存是个问题,但我可以任其发展。

为了让它正常工作,我必须创建UIDocument的子类并重写
func save(to:for:completionHandler:)

您的代码保持完全相同,只需确保
self.document
的类型为
MyDocument
(或者您可能已经拥有的任何子类)


移除完成块不会导致崩溃。更多信息:
MyDocument.contents:forType:
确实会被调用,因此我知道保存已启动。这就好像UIDocument中的某些内容被强制在主线程/队列上运行,尽管我在一个新的调度队列上显式地启动了它,这似乎太奇怪了。我认为您误解了建议,请尝试将保存代码放在主线程上,而不是放在
self.saveQueue.async
后面。那么代码应该崩溃了。更好的是,让代码保持原样,并为
objc\u exception\u throw添加符号断点。这是我做的第一件事。但是:“典型的基于文档的应用程序调用open(completionHandler:)、close(completionHandler:)和save(to:for:completionHandler:)在主线程上。当这些方法启动的读取或保存操作结束时,完成处理程序块将在调用该方法的同一调度队列上执行,从而允许您完成任何与读取或保存操作相关的任务。如果操作不成功,则将false传递给完成处理程序块。”[即使在删除
saveQueue.async
时也不会崩溃,在保存完成块内移动
saveQueue.async
时也不会崩溃。使用调度队列时不会调用完成块。在删除调度队列和信号量时,完成块在
activityViewController:itemFor之后执行ActivityType
returns.hmm,好的。我会继续挖掘,看看是否能正确保存它!我也有同样的事情发生,完成块在异步之后不会触发
override func save(to url: URL, for saveOperation: UIDocument.SaveOperation, completionHandler: ((Bool) -> Void)? = nil) {
    do {
        let contents = try self.contents(forType: GlobalConst.exportType) as! Data
        try contents.write(to: url, options: [.atomicWrite])
        completionHandler?(true)
    } catch {
        print("write error: \(error)")
        completionHandler?(false)
    }
}
class MyDocument: UIDocument {

    var body: String = "Hello world, this is example content!"

    override func save(to url: URL, for saveOperation: UIDocument.SaveOperation, completionHandler: ((Bool) -> Void)? = nil) {
        do {
            try self.body.write(toFile: url.path, atomically: true, encoding: .utf8)
            completionHandler?(true)
        } catch {
            print("write error: \(error)")
            completionHandler?(false)
        }
    }
}
let document = MyDocument(fileURL: URL(fileURLWithPath: NSHomeDirectory() + "/Documents/output.txt"))