显示带有“请稍候”消息的对话框。然后遍历扩展上下文的inputItems 两次:一次只是为了计算我们想要处理的文件数,然后再一次是为了实际处理它们。当处理的文件数量等于我们预期的数量时,我们调用另一个实例方法来隐藏对话框并将控制权返回给宿主应用程序。
为了线程安全,处理的数字的递增以及处理的数字与预期数字之间的比较是在序列号DispatchQueue 上完成的。这确保了即使传递给loadFileRepresentation 的块的多个副本同时运行,扩展仍然能够正确识别何时处理完文件。
import UIKit
class ShareViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
return
}
// Display a "please wait" message while we copy the files.
let alertVC = UIAlertController(title: nil,
message: "Processing files…",
preferredStyle: .alert)
present(alertVC, animated: false, completion: nil)
// Iterate through the files once, incrementing "numberExpected" each
// time we see a file we're interested in.
var numberExpected: Int = 0
for item in items {
guard let attachments = item.attachments else {
continue
}
for attachment in attachments {
if attachmentShouldBeProcessed(attachment) {
numberExpected += 1
}
}
}
// Iterate through the files again, actually processing them this time.
// After each file is done--whether it succeeded or not--we increment
// "numberProcessed" and compare it to "numberExpected". (It's very
// important that this be done in a thread-safe way, which we accomplish
// here by doing the comparison within a block that is run on a serial
// DispatchQueue.) If they're equal, call the finish() method to close
// the progress dialog and return control of the UI to the host app.
var numberProcessed: Int = 0
let queue = DispatchQueue(label: "com.myapp.file-processing-queue")
for item in items {
guard let attachments = item.attachments else {
continue
}
for attachment in attachments {
guard attachmentShouldBeProcessed(attachment) else {
continue
}
attachment.loadFileRepresentation(forTypeIdentifier: "public.png") { url, error in
// ...your business logic here...
queue.sync {
numberProcessed += 1
if numberProcessed == numberExpected {
DispatchQueue.main.async { [weak self] in
self?.finish()
}
}
}
}
}
}
}
func finish() {
// Dismiss the "processing items" dialog.
dismiss(animated: false, completion: nil)
// Inform the host app that we're done so it can un-block its UI.
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
func attachmentShouldBeProcessed(_ attachment: NSItemProvider) -> Bool {
// ...your business logic here...
return true
}
}