使用UIDocumentBrowserViewController创建文档

时间:2017-07-27 05:17:01

标签: ios nsfilemanager ios11 uidocument uidocumentbrowservc

documentBrowser(_:didRequestDocumentCreationWithHandler:)的文档说:“创建一个新文档并将其保存到临时位置。如果使用UIDocument子类创建文档,则必须在调用{{}之前关闭它。 1}}阻止。“

所以我通过获取用户临时目录(importHandler)的URL并附加名称和扩展名(获取类似“file:/// private / var / mobile / Containers /的路径)来创建文件URL数据/应用/ C1DE454D-EA1E-4166-B137-5B43185169D8 / TMP / Untitled.uti“)。但是当我调用FileManager.default.temporaryDirectory传递此URL时,永远不会回调完成处理程序。我还尝试使用save(to:for:completionHandler:)传递用户临时目录中的子目录 - 仍未调用完成处理程序。

我理解文档浏览器视图控制器由一个单独的进程管理,该进程有自己的读/写权限。除此之外,我很难理解问题所在。临时保存新文档的位置,以便文档浏览器进程可以移动它们?

更新:截至目前的测试版,我现在看到域url(for:in:appropriateFor:create:)和代码NSFileProviderInternalErrorDomain出现错误:“不允许读者访问该网址。”至少那是对发生的事情的确认......

3 个答案:

答案 0 :(得分:10)

因此,首先,如果您使用的是自定义UTI,则必须正确设置。我看起来像这样......

-Dlogback.configurationFile

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeIconFiles</key>
        <array>
            <string>icon-file-name</string> // Can be excluded, but keep the array
        </array>
        <key>CFBundleTypeName</key>
        <string>Your Document Name</string>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>LSHandlerRank</key>
        <string>Owner</string>
        <key>LSItemContentTypes</key>
        <array>
            <string>com.custom-uti</string>
        </array>
    </dict>
</array>

另外

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.data</string>  // My doc is saved as Data, not a file wrapper
        </array>
        <key>UTTypeDescription</key>
        <string>Your Document Name</string>
        <key>UTTypeIdentifier</key>
        <string>com.custom-uti</string>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <array>
                <string>doc-extension</string>
            </array>
        </dict>
    </dict>
</array>

我将<key>UISupportsDocumentBrowser</key> <true/> 子类化为UIDocument并添加以下方法来创建新的临时文档...

MyDocument

然后按如下方式初始化并显示DBVC:

static func create(completion: @escaping Result<MyDocument> -> Void) throws {

    let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Untitled").appendingPathExtension("doc-extension")

    coordinationQueue.async {
        let document = MyDocument(fileURL: targetURL)
        var error: NSError? = nil
        NSFileCoordinator(filePresenter: nil).coordinate(writingItemAt: targetURL, error: &error) { url in
            document.save(to: url, for: .forCreating) { success in
                DispatchQueue.main.async {
                    if success {
                        completion(.success(document))
                    } else {
                        completion(.failure(MyDocumentError.unableToSaveDocument))
                    }
                }
            }
        }
        if let error = error {
            DispatchQueue.main.async {
                completion(.failure(error))
            }
        }
    }
}

我的委托方法如下:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    lazy var documentBrowser: UIDocumentBrowserViewController = {
        let utiDecs = Bundle.main.object(forInfoDictionaryKey: kUTExportedTypeDeclarationsKey as String) as! [[String: Any]]
        let uti = utiDecs.first?[kUTTypeIdentifierKey as String] as! String
        let dbvc = UIDocumentBrowserViewController(forOpeningFilesWithContentTypes:[uti])

        dbvc.delegate = self
        return dbvc
    }()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = documentBrowser
        window?.makeKeyAndVisible()

        return true
    }
}

这就是它。让我知道你是如何上场的!

答案 1 :(得分:3)

我有同样的问题,但后来我意识到推荐的方法是简单地从Bundle中复制包/文件夹,如下所示:

func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {
    if let url = Bundle.main.url(forResource: "Your Already Created Package", withExtension: "your-package-extension") {
        importHandler(url, .copy)
    } else {
        importHandler(nil, .none)
    }
}

为了澄清一下,这个包只是你创建的一个文件夹,并且已经填入Xcode。

如果您考虑这个问题,这种方法很有意义,原因如下:

  1. Apple文件系统(AFS)。向AFS的转变意味着复制(几乎)是免费的。

  2. 权限。始终允许从Bundle复制,并且用户正在指定要复制到的位置。

  3. 新文档浏览器范例。由于我们正在使用新的UIDocumentBrowserViewController范例(由于iOS11和新的文件应用程序),它甚至可以处理命名(例如Apple的页面)以及移动和排列文件。我们不必担心在哪个线程上运行。

  4. 因此。更简单,更容易,也可能更好。我想不出手动创建所有文件的原因(或使用临时文件夹等)。

答案 2 :(得分:1)

在设备上测试,而不是在模拟器中。我在设备上切换到测试的那一刻,一切都刚刚开始正常工作。 (注意:模拟器故障可能仅发生在像我这样的Sierra用户身上。)