使用文件提供程序实现UIDocumentPickerModeOpen

时间:2015-03-24 20:57:05

标签: ios objective-c ios-app-extension

是否有人成功实施过" open"文件提供商应用扩展程序的操作?当用户最初在文档选择器扩展中选择文件时,我已经能够读取文件(基本上,这是" import"操作)。但是,除此之外的任何事情以下是我遇到的问题:

  • 如果我使用NSFileCoordinator,则应用会死锁。
  • 如果我保存URL并尝试稍后读取或写入,则对startAccessingSecurityScopedResource的调用将返回NO 如果我使用书签,则此方法有效
  • 如果我尝试bookmarkDataWithOptions:,我会回来错误域= NSCocoaErrorDomain Code = 260"操作无法完成。 (可可错误260。)" 如果我在安全范围内创建书签,则此方法有效。

以下是创建文件提供程序扩展时为startProvidingItemAtURL:创建的模板:

- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler {
    // Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler
    NSError* error = nil;
    __block NSError* fileError = nil;

    NSData * fileData = [NSData data];
    // TODO: get the contents of file at <url> from model

    [self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
        [fileData writeToURL:newURL options:0 error:&fileError];
    }];
    if (error!=nil) {
        completionHandler(error);
    } else {
        completionHandler(fileError);
    }
}

但是当我使用文件协调器时,扩展会出现死锁。此外,startProvidingItemAtURL:的文档说明了&#34; 注意 不要在此方法中使用文件协调。&#34; 所以我已经把它拿出来了。

在另一个应用程序中,这是我第一次阅读该文件然后为其创建书签时所做的事情:

// Start accessing the security scoped resource.
[url startAccessingSecurityScopedResource];

void (^accessor)(NSURL *) = ^void(NSURL *url) {
  // If the file is missing, create a default here. This really should be done inside
  // the FileProvider method startProvidingItemAtURL:. Unfortunately, that method does
  // not get called unless we use use the file coordinator, which can deadlock the app.
  if (![url checkResourceIsReachableAndReturnError:nil]) {
    // TODO: Create a real default file here.
    [[NSFileManager defaultManager] createFileAtPath:url.path
                                            contents:nil
                                          attributes:nil];
  }

  // TODO: Do something with this file.
};

#ifdef USE_FILE_COORDINATOR
NSFileCoordinator *fileCoordinator = [NSFileCoordinator new];
[fileCoordinator coordinateReadingItemAtURL:url
                                    options:NSFileCoordinatorReadingWithoutChanges
                                      error:NULL
                                 byAccessor:accessor];
#else
accessor(url);
#endif

// Store a bookmark for the url in the defaults so we can use it later.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSError *error = nil;
NSURLBookmarkCreationOptions options = 0;
#ifdef NSURLBookmarkCreationWithSecurityScope
options |= NSURLBookmarkCreationWithSecurityScope;
#endif
NSData *bookmarkData = [url bookmarkDataWithOptions:options
                     includingResourceValuesForKeys:nil
                                      relativeToURL:nil
                                                error:&error];
if (error) {
  NSLog(@"ERROR: %@", error);
}
[defaults setObject:bookmarkData forKey:@"BookmarkDataKey"];

// Stop accessing the security scoped resource.
[url stopAccessingSecurityScopedResource];

最后,为了稍后使用书签,我正在执行以下操作:

// Get the bookmark from the defaults file.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *bookmarkData = [defaults objectForKey:@"BookmarkDataKey"];
if (bookmarkData) {
  // Convert the bookmark into a URL.
  NSError *error;
  BOOL bookmarkIsStale;
  NSURLBookmarkResolutionOptions options = NSURLBookmarkResolutionWithoutUI;
#ifdef NSURLBookmarkResolutionWithSecurityScope
  options |= NSURLBookmarkResolutionWithSecurityScope;
#endif

  NSURL *url = [NSURL URLByResolvingBookmarkData:bookmarkData
                                         options:options
                                   relativeToURL:nil
                             bookmarkDataIsStale:&bookmarkIsStale
                                           error:&error];

  // Get the data from the URL.
  BOOL securitySucceeded = [url startAccessingSecurityScopedResource];
  if (securitySucceeded) {
    NSString *message = [NSString stringWithFormat:@"Random number: #%d", arc4random() % 10000];
    NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
    NSError *fileError = nil;
    [fileData writeToURL:url options:0 error:&fileError];

    [url stopAccessingSecurityScopedResource];
  }
}

如果我使用文件协调,第二个应用程序有时也会死锁。那么我应该在第二个应用程序中不使用文件协调吗?问题是如果我不使用文件协调,那么文件提供程序扩展中的startProvidingItemAtURL:似乎永远不会被调用。

此外,the documentation says使用NSURLBookmarkCreationWithSecurityScope,但iOS未定义。 NSURLBookmarkResolutionWithSecurityScope也是如此。我应该只使用OS X值还是不使用它们?

2 个答案:

答案 0 :(得分:2)

最后,我认为我已经通过在任何地方删除文件协调并忽略安全范围书签常量来实现它。以下是我在文件提供程序扩展中用于startProvidingItemAtURL:的内容:

- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler {
  // If the file doesn't exist then create one.
  if (![url checkResourceIsReachableAndReturnError:nil]) {
    __block NSError *fileError = nil;
    NSString *message = @"This is a test message";
    NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
    [fileData writeToURL:url options:0 error:&fileError];
    completionHandler(fileError);
  }
}

在另一个应用程序中,这是我第一次阅读该文件然后为其创建书签时所做的事情:

// Start accessing the security scoped resource.
[url startAccessingSecurityScopedResource];

// If the file is missing, create a default here. This really should be done inside
// the FileProvider method startProvidingItemAtURL:. Unfortunately, that method does
// not get called unless we use use the file coordinator, which can deadlock the app.
if (![url checkResourceIsReachableAndReturnError:nil]) {
  // TODO: Create a real default file here.
  [[NSFileManager defaultManager] createFileAtPath:url.path
                                          contents:nil
                                        attributes:nil];
// TODO: Do something with this file.

// Store a bookmark for the url in the defaults so we can use it later.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSError *error = nil;
NSURLBookmarkCreationOptions options = 0;
#ifdef NSURLBookmarkCreationWithSecurityScope
options |= NSURLBookmarkCreationWithSecurityScope;
#endif
NSData *bookmarkData = [url bookmarkDataWithOptions:options
                     includingResourceValuesForKeys:nil
                                      relativeToURL:nil
                                                error:&error];
if (error) {
  NSLog(@"ERROR: %@", error);
}
[defaults setObject:bookmarkData forKey:@"BookmarkDataKey"];

// Stop accessing the security scoped resource.
[url stopAccessingSecurityScopedResource];

最后,为了稍后使用书签,我正在执行以下操作:

// Get the bookmark from the defaults file.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *bookmarkData = [defaults objectForKey:@"BookmarkDataKey];
if (bookmarkData) {
  // Convert the bookmark into a URL.
  NSError *error;
  BOOL bookmarkIsStale;
  NSURLBookmarkResolutionOptions options = NSURLBookmarkResolutionWithoutUI;
#ifdef NSURLBookmarkResolutionWithSecurityScope
  options |= NSURLBookmarkResolutionWithSecurityScope;
#endif

  NSURL *url = [NSURL URLByResolvingBookmarkData:bookmarkData
                                         options:options
                                   relativeToURL:nil
                             bookmarkDataIsStale:&bookmarkIsStale
                                           error:&error];

  // Get the data from the URL.
  BOOL securitySucceeded = [url startAccessingSecurityScopedResource];
  if (securitySucceeded) {
    NSString *message = [NSString stringWithFormat:@"Random number: #%d", arc4random() % 10000];
    NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
    NSError *fileError = nil;
    [fileData writeToURL:url options:0 error:&fileError];

    [url stopAccessingSecurityScopedResource];
  }
}

答案 1 :(得分:0)

您不应该调用文件协调器调用:staringProvidingItemsAtUrl
检查方法的苹果评论,并说:
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler
Note
Do not use file coordination inside this method. The system already guarantees that no other process can access the file while this method is executing.

删除后:
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL)
僵局应该消失。
也: NSURLBookmarkCreationWithSecurityScope
不适用于IOS和IOS没有此选项。 IOS不需要此选项。苹果文件非常混乱。