2

我不知道如何解决这个问题。每次用户滚动并在 UITableView 中显示时,此代码都会在每个单元格中运行:

self.isFinishedProcessing = NO;

    [self setNeedsDisplay];

    [self.mediaArray removeAllObjects];
    self.mediaArray = [[NSMutableArray alloc] init];

    dispatch_queue_t queue = dispatch_queue_create("setup_cell", NULL);

    NSManagedObjectID *objectID = [self.entry objectID];
    dispatch_async(queue, ^{

        CoreDataStore *customStore = [CoreDataStore createStore];

        Entry *entry = (Entry *)[customStore.context objectWithID:objectID];

        if (self.cellInfo.numberOfMediaItems > 0) {

            int i = 0;

            int numberOfThumbnails = MIN(self.cellInfo.numberOfMediaItems, 3);

            while (i < numberOfThumbnails) {
                Media *media = [entry.media objectAtIndex:i];

                UIImage *image = [media getThumbnail];
                [self.mediaArray addObject:image];

                i++;
            }
        }

        dispatch_async(dispatch_get_main_queue(), ^{

            self.isFinishedProcessing = YES;
            [self setNeedsDisplay];
        });

    });

核心数据存储将作为核心数据类的条目与媒体一起放入它自己的上下文中。

我还没有弄清楚滚动时这段代码何时崩溃,但它在上下滚动几次时会发生。

编辑:“索引对象”之前的 NSLog 表示计数为 3。可以肯定的是,我实际上为此做了 entry.media.count。

这是完整的错误:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

编辑2:

还没有解决这个问题。我在最后添加了这个:

        if (self.mediaArray.count != self.entry.media.count) {
        NSLog(@"INCORRECT BECAUSE.... media array count: %i, entry media count: %i number of media items: %i", self.mediaArray.count, self.entry.media.count, self.cellInfo.numberOfMediaItems);
        }

它经常在一个像这样的单元格之后崩溃:

INCORRECT BECAUSE.... media array count: 1, entry media count: 3 number of media items: 3

不确定媒体数组计数如何可能是错误的,如果它是根据 self.cellInfo.numberOfMediaItems 创建的。

还值得注意的是,这只发生在单独的线程中。永远不会在主线程中崩溃。

4

1 回答 1

6

您违反了具有多个线程的 Core Data规则 #1

您不得在线程中使用 MOC,除非它是在该线程中创建的。

您创建一个队列来为您运行一些工作......

dispatch_queue_t queue = dispatch_queue_create("setup_cell", NULL);

然后在那个块中,您使用的是不是在那里创建的 MOC ......

Entry *entry = (Entry *)[customStore.context objectWithID:objectID];

如果你想和 MOC 一起工作,你必须遵守规则。我将总结规则#1,因为它有几个子句。

  • 如果您使用 创建 MOC NSConfinementConcurrencyType,则无法调用performBlock该上下文。您只能在创建它的线程中使用它。

  • 如果使用NSMainQueueConcurrencyType,则必须从主线程内访问 MOC,或通过[moc performBlock].

  • 如果您使用NSPrivateQueueConcurrencyType,则必须仅通过 使用它[moc performBlock]

编辑

您的项目不同步。您应该只依靠数据实际告诉您的内容。显然,您指望来自 self.cellInfo.numberOfMediaItems 的计数,但它与您的实际数据不同步。

从多个线程更新数据时必须非常小心。您的代码“迷失了”实际发生的事情。可能是因为您尚未将内容保存到从中提取数据的上下文中。

阅读有关 Core Data 并发的文档。确保在没有通知所有其他上下文的情况下没有更改另一个线程中的任何内容。您应该使用父/子上下文和/或处理 DidSave 通知以保持数据同步。

于 2012-06-02T22:56:20.153 回答