UIManagedDocument Singleton代码openWithCompletionHandler调用两次并崩溃

Wil*_*dan 6 singleton ios uimanageddocument

我正在使用Justin Driscoll在Core Data上使用单个共享UIManagedDocument实现.我的iphone应用程序中的一切都很好,直到我将它移动到iPad故事板和ipad应用程序的splitview控制器.问题是openwithCompletionHandler被调用两次,一次来自viewDidLoad中的主视图,另一次是我的详细视图viewWillLoad.这些调用是快速连续的,因为当对单例的performWithDocument方法(下面)进行第二次调用时,文档仍然在UIDocumentStateClosed中,应用程序崩溃.我查看了e_x_p对iOS5.1后的回答:同步任务(等待完成)但@sychronized在这种情况下不起作用,因为下面的performWithDocument是在同一个线程上调用的.我如何防止多次调用openwithCompletionHandler?我能想到防止这种情况的唯一方法是暂停执行上面的一个调用,直到我确定UIDocumentStateNormal为true然后释放.这虽然会冻结主要的UI线程,这是不好的.尽管如此,如果没有冻结用户界面,最好的办法是什么呢?

从UIManagedDocumentSingleton代码:

- (void)performWithDocument:(OnDocumentReady)onDocumentReady
{
    void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success)
    {
        onDocumentReady(self.document);
    };

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]])
    {
        //This should never happen*******************
        [self.document saveToURL:self.document.fileURL
                forSaveOperation:UIDocumentSaveForCreating
               completionHandler:OnDocumentDidLoad];

    } else if (self.document.documentState == UIDocumentStateClosed) {
        [self.document openWithCompletionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateNormal) {
        OnDocumentDidLoad(YES);
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*han 0

之间共享的代码块numberOfRowsInSection:只能cellForRowAtIndexPath:被调用一次。将始终在尝试渲染单元格numberOfRowsInSection之前被调用,因此您应该创建一个可以将获取请求的结果存储到其中的对象,然后在渲染单元格时使用此数组:tableViewNSArray

@implementation FooTableViewController {
    NSArray *_privateArray;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    [[UIManagedDocumentSingletonHandler sharedDocumentHandler] performWithDocument:^(FCUIManagedDocumentObject *document) {
        NSManagedObjectContext * context =  document.managedObjectContext;

        NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"FCObject"];
        NSPredicate * searchStringPredicate = nil;
        if (searchFilterString)
        {
            searchStringPredicate = [NSPredicate predicateWithFormat:@"word BEGINSWITH[c] %@",searchFilterString];
        }
        request.predicate = searchStringPredicate;
        request.shouldRefreshRefetchedObjects = YES;
        NSError * error;
        _privateArray = [context executeFetchRequest:request error:&error];
        }];
    return _privateArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"FCCell";
    FCardCell *cell = (FCCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Configure the cell...
    FCManagedObject * fcc = [_privateArray objectAtIndex:indexPath.row];
    cell.isWordVisible.on = fcc.isUsed;
    cell.fWord.text = fcc.word;
    return cell;
}
Run Code Online (Sandbox Code Playgroud)

我不确定您是否需要做一些特殊的事情来将NSArray其设置在块内(a la __block)。

主要原因是您需要确保用于确定行数的数据集 100% 的大小与创建单元格时的大小相同。如果它们不匹配,那么你就会崩溃。此外,由于您没有阻止,因此您现在不需要调度来进行UITableViewCell更新。

最后,如果UIDocumentStateClosed导致问题,您应该将它们从NSFetch结果中过滤掉(附加谓词,看看NSCompoundPredicate是否需要),或者使用代码来更好地处理它们cellForRowAtIndexPath: