我已经花了几天时间尝试寻找或自己弄清楚如何在通知 UIDocumentStateChangedNotification 触发且文档状态发生变化时以编程方式合并 UIDocument 更改UIDocumentStateInConflict 设置。
我能找到的所有示例(Apples、Ray Wenderlich 等)都详细说明了提示用户选择版本 方法。
我找不到任何演示以编程方式合并的正确方法。
这让我很担心,因为它让我认为它太不稳定而无法信任并且通常被避免作为解决方案?
到目前为止,我在这方面的经验加强了这一立场。
让我详细说明我尝试中的每个问题区域。
1) 为了合并的目的,读取当前文档内容和 NSFileVersion 冲突版本的正确方法是什么?
使用任何带有完成 block 的东西在同步时真的很麻烦。 UIDocument 的 openWithCompletionHandler: 不值得使用。
事实上,作为一项规则,只读 UIDocument 的推荐方法是什么?为什么打开文档只是为了阅读?
我尝试使用 UIDocument 的 readFromURL:,这对于当前文档来说很好,但如果我尝试在任何 NSFileVersion 上使用它的
冲突版本它读取当前版本,而不是 URL 上的版本(我使用 MacOS 终端深入挖掘 ../data/.DocumentRevisions-V100/PerUID/... 文件以确认这一点。)。
对于冲突版本,它对我有用的唯一方法是直接读取访问这些文件。 (例如 NSData initWithContentsOfFile:)
2) 一旦读入文件的变体,并设法合并,如何正确保存合并?
这个在我能找到的任何地方都没有记录。
我成功的唯一方法是重新使用 NSFileVersion 的冲突文件之一,覆盖它,然后使用 UIDocument 的 replaceItemAtURL: 使其成为最新的。
在使用 replaceItemAtURL: 之后,我还尝试使用 UIDocument 的 revertToContentsOfURL:,但它只是在没有给出任何理由的情况下崩溃。由于没有它合并似乎可以正常工作,因此我并不担心,但我认为我会将其作为细节包含在内。
3) iPhone/iPad 模拟器 (V10.0) 在我重新启动应用程序之前不会通知冲突。这是可以预料的还是我做错了什么?我问是因为在模拟器的 Debug 菜单下有 Trigger iCloud Sync 可以同步,但在下次应用重新启动之前不会标记冲突。这只是模拟器的限制吗?
谢谢,
Best Answer-推荐答案 strong>
经过几周的测试和了解哪些有效,哪些无效后,我简化了我的 UIDocument 合并代码。
我做出的错误假设之一是需要将 UIDocument 的 revertToContentsOfURL: 作为解析过程的一部分。
这是一个非常不稳定的 API 调用,我发现最好避免,即使在 @try() 中使用它也不能防止不必要的崩溃。
这让我删除它只是为了看看会发生什么,如果没有它,冲突就会很好地解决。
在 developer.apple.com 上有文档冲突解决的示例代码,暗示应该使用它。
它似乎在 WWDC2018 之后消失了。
剩下的唯一问题是,如果您有 2 台设备同时打开,您可能会进入竞争状态,因为它们会不断合并文档。
我之前经历过零冲突版本,尽管文档被标记为冲突,但最近我没有看到这种情况发生。一定是我之前做错了什么。我将代码保留在那里,因为它没有害处。
我认为这里值得一提的另一个问题是,如果您是 UIDocument 的新手,请记住它是 UIKit 的一部分,您需要确保在主线程上完成更新。我找到了this useful tip这解决了我仍然遇到的一些剩余问题。
- (void) foobar {
[[NSNotificationCenter defaultCenter] addObserver:self
selectorselector(handleDocumentStateChange
name:UIDocumentStateChangedNotification
object:_myDocument];
}
- (void) handleDocumentStateChange: (NSNotification *) notification {
if (_myDocument.documentState & UIDocumentStateInConflict) {
if (_resolvingConflicts) {
return;
}
NSArray *conflictVersions = [NSFileVersion unresolvedConflictVersionsOfItemAtURL:_myDocument.fileURL];
if ([conflictVersions count] == 0) {
return;
}
NSMutableArray *docs = [NSMutableArray new];
[docsData addObject:_myDocument.data]; // Current document data
_resolvingConflicts = YES;
for (NSFileVersion *conflictVersion in conflictVersions) {
MyDocument *myDoc = [[MyDocument alloc] initWithFileURL:conflictVersion.URL];
NSError *error;
[myDoc readFromURL:conflictVersion.URL error:&error];
if ((error == Nil) && (myDoc.data != Nil)) {
[docs addObject:myDoc.data];
}
}
if ([self mergeDocuments:docs]) {
[self saveChangesToDocument];
}
for (NSFileVersion *fileVersion in conflictVersions) {
fileVersion.resolved = YES;
}
[self deleteiCloudConflictVersionsOfFile:_myDocument.fileURL
completion:^(BOOL success){
self.resolvingConflicts = NO;
dispatch_async(dispatch_get_main_queue(), ^{
// On main thread for UI updates
[[NSNotificationCenter defaultCenter] postNotificationName:kMyDocsUpdateNotification object:nil];
});
}];
}
}
- (void) deleteiCloudConflictVersionsOfFile : (NSURL *) fileURL {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:fileURL
options:NSFileCoordinatorWritingForDeleting
error:nil
byAccessor:^(NSURL* writingURL) {
NSError *error;
if ([NSFileVersion removeOtherVersionsOfItemAtURL:writingURL error:&error]) {
NSLog(@"deleteiCloudConflictVersionsOfFile: success");
} else {
NSLog(@"deleteiCloudConflictVersionsOfFile: error; %@", [error description]);
}
}];
});
}
关于ios - 合并 iCloud 冲突的 UIDocument 更改,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/50653387/
|