iCloud保存数据与UIDocument崩溃

Posted

技术标签:

【中文标题】iCloud保存数据与UIDocument崩溃【英文标题】:iCloud Save data With UIDocument crash 【发布时间】:2012-08-13 01:31:03 【问题描述】:

我正在尝试使用 iCloud 来存储我的应用程序的 userSetting,这是我的 Save & Load Code: ,它通常运行良好,但有时会崩溃并显示如下消息:尝试打开或恢复已经打开的文档或在飞行中恢复操作发送到dealloc实例所以我在openWithCompletionHandler之前添加fileState日志它总是显示状态= UIDocumentStateClosed无论是否会崩溃,我在applecationDidEnterBackground时保存数据并在applicationDidBecomeActive时加载.

保存:

-(void)storeToiCloud
    NSURL *baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (baseURL) 
        NSURL *documentsURL = [baseURL URLByAppendingPathComponent:@"Documents"];
        NSURL *documentURL = [documentsURL URLByAppendingPathComponent:[NSString stringWithFormat:@"userSetting"]];
        if (!loadDocument) 
            self.loadDocument = [[MyUserDefaultsDocument alloc] initWithFileURL:documentURL];
        
        loadDocument.myUserDefault = [MyUserDefaults standardUserDefaults];

        [loadDocument saveToURL:documentURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) 
        ];
    

加载:

-(BOOL)shouldSynciCloud
    if (![Utility iCloudEnable]) 
        return NO;
    
    NSURL *baseURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (baseURL) 
        self.query = [[[NSMetadataQuery alloc] init] autorelease];
        [self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == 'userSetting'", NSMetadataItemFSNameKey];
        [self.query setPredicate:predicate];

        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(queryDidFinish:) name:NSMetadataQueryDidFinishGatheringNotification object:self.query];

        [self.query startQuery];
        [Utility showSpinner];
        return YES;
    
    return NO;


- (void)queryDidFinish:(NSNotification *)notification 
    NSMetadataQuery *query = [notification object];

    // Stop Updates
    [query disableUpdates];
    // Stop Query
    [query stopQuery];
    [query.results enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 

        NSURL *documentURL = [(NSMetadataItem *)obj valueForAttribute:NSMetadataItemURLKey];

        if([[documentURL lastPathComponent] hasPrefix:@"userSetting"])
            self.document = [[MyUserDefaultsDocument alloc] initWithFileURL:documentURL];
            NSString* message;
            if (document.documentState == UIDocumentStateNormal)
                message = @"UIDocumentStateNormal";
            else if (document.documentState == UIDocumentStateClosed) 
                message = @"UIDocumentStateClosed";
            else if(document.documentState == UIDocumentStateEditingDisabled)
                message = @"UIDocumentStateEditingDisabled";
            else if(document.documentState == UIDocumentStateInConflict)
                message = @"UIDocumentStateInConflict";
            else if(document.documentState == UIDocumentStateSavingError)
                message = @"UIDocumentStateSavingError";
            
            NSLog(@"state = %@",message);
            [document openWithCompletionHandler:^(BOOL success) 
                if (success) 
                    MyUserDefaults *prefs = [MyUserDefaults standardUserDefaults];                    
                    NSData *book =[document.myUserDefault.realDict objectForKey:@"realbook"];
                    NSData *readSetting = [document.myUserDefault.realDict objectForKey:@"epubRS"];

                    if (book&&[[NSUserDefaults standardUserDefaults] boolForKey:@"iCloudBook"]) 
                        [prefs setObject:book forKey:@"realbook"];
                        [Utility reloadRealBooks];
                    
                    if (readSetting&&[[NSUserDefaults standardUserDefaults] boolForKey:@"iCloudSetting"]) 
                        [prefs setObject:readSetting forKey:@"epubRS"];
                        [Utility setEpubReadSettingFromData:readSetting];
                    
                    [prefs save];

                    [[NSNotificationCenter defaultCenter]postNotificationName:@"iCloudSynced" object:nil];
                    [Utility removeSpinner];
                
                else
                    [[NSNotificationCenter defaultCenter]postNotificationName:@"iCloudSyncfailed" object:nil];
                    [Utility removeSpinner];
                
            ];
        
    ];
    if ([query.results count]==0) 
        [[NSNotificationCenter defaultCenter]postNotificationName:@"iCloudSyncfailed" object:nil];
        [Utility removeSpinner];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:nil];

【问题讨论】:

【参考方案1】:

如this question 中所述,如果您的应用尝试连续两次调用 [document openWithCompletionHandler:] 方法,则会发生错误。

由于openWithCompletionHandler: 异步打开文档,再次调用该方法时,文档可能还在打开中。

如果发生这种情况,您的应用最终会尝试打开文档两次(因为文档状态将保持 UIDocumentStateClosed 直到完成),这会导致引发异常。

【讨论】:

我已经通过更改我的代码解决了这个问题,但是当我在 applicationDidEnterBackground 写 [loadDocument saveToURL:documentURL forSaveOperation:UIDocumentSaveForCreating completionHandler:nil] 时,我的文件有时无法同步到 iCloud

以上是关于iCloud保存数据与UIDocument崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在本地保存 UIDocument

UIDocument 打开/关闭行为

在哪里存储 UIDocument 的预览?

我如何将 FMDatabase 存储到 iCloud

iOS 查询更新不起作用

在没有 UIDocument 的情况下获取 iCloud URL 的数据内容