使用文件提供程序实现 UIDocumentPickerModeOpen
Implementing UIDocumentPickerModeOpen with File Providers
有没有人为文件提供程序应用程序扩展成功实施 "open" 操作?当用户最初在文档选择器扩展中选择文件时,我已经能够读取文件(本质上,这是 "import" 操作)。但除此之外的任何事情都失败了。以下是我 运行 遇到的问题:
- 如果我使用
NSFileCoordinator
,应用程序会死锁。
如果我保存 URL 并稍后尝试读取或写入它,调用 startAccessingSecurityScopedResource
returns NO
. 如果我使用书签就可以了。
如果我尝试 bookmarkDataWithOptions:
,我会返回 Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 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:
的文档说 "Note
不要在这个方法中使用文件协调。" 所以我把它去掉了。
在另一个应用程序中,这是我第一次读取该文件然后为其创建书签的操作:
// 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 值还是不使用它们?
最后,我想我已经通过删除各处的文件协调并忽略安全范围书签常量来实现它。这是我在文件提供程序扩展中用于 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];
}
}
你不应该调用文件协调器调用:staringProvidingItemsAtUrl
检查该方法的苹果评论,它说:
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler<br>
注意<br>
不要在此方法中使用文件协调。系统已经保证在该方法执行过程中没有其他进程可以访问该文件。
删除后:
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL)
死锁应该会消失。
还:
NSURLBookmarkCreationWithSecurityScope
不适用于 IOS 并且 IOS 没有此选项。 IOS 不需要此选项。苹果文档对此非常混乱。
有没有人为文件提供程序应用程序扩展成功实施 "open" 操作?当用户最初在文档选择器扩展中选择文件时,我已经能够读取文件(本质上,这是 "import" 操作)。但除此之外的任何事情都失败了。以下是我 运行 遇到的问题:
- 如果我使用
NSFileCoordinator
,应用程序会死锁。 如果我保存 URL 并稍后尝试读取或写入它,调用如果我使用书签就可以了。startAccessingSecurityScopedResource
returnsNO
.如果我尝试如果我在安全范围内创建书签,这会起作用。bookmarkDataWithOptions:
,我会返回 Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 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:
的文档说 "Note
不要在这个方法中使用文件协调。" 所以我把它去掉了。
在另一个应用程序中,这是我第一次读取该文件然后为其创建书签的操作:
// 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 值还是不使用它们?
最后,我想我已经通过删除各处的文件协调并忽略安全范围书签常量来实现它。这是我在文件提供程序扩展中用于 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];
}
}
你不应该调用文件协调器调用:staringProvidingItemsAtUrl
检查该方法的苹果评论,它说:
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler<br>
注意<br>
不要在此方法中使用文件协调。系统已经保证在该方法执行过程中没有其他进程可以访问该文件。
删除后:
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL)
死锁应该会消失。
还:
NSURLBookmarkCreationWithSecurityScope
不适用于 IOS 并且 IOS 没有此选项。 IOS 不需要此选项。苹果文档对此非常混乱。