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