我的代码在使用核心数据时会因"索引超出边界"错误而崩溃

And*_*rew 2 iphone core-data objective-c ios

我不知道如何解决这个问题.每次用户滚动时,此代码都会在每个单元格中运行,并在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];
        });

    });
Run Code Online (Sandbox Code Playgroud)

核心数据存储采用Entry(核心数据类)和Media,并将其置于自己的上下文中.

我还没有弄清楚滚动时这个代码崩溃的确切时间,但是在向上和向下滚动几次时会发生这种情况.

编辑:在'索引对象'之前的NSLog说有一个计数3.我实际上做了entry.media.count,当然.

这是完整的错误:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
Run Code Online (Sandbox Code Playgroud)

编辑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);
        }
Run Code Online (Sandbox Code Playgroud)

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

INCORRECT BECAUSE.... media array count: 1, entry media count: 3 number of media items: 3
Run Code Online (Sandbox Code Playgroud)

如果它依赖于self.cellInfo.numberOfMediaItems创建,则不确定媒体数组计数可能是错误的.

另外值得注意的是,只有在单独的线程中完成时才会发生这种情况.永远不会在主线程中崩溃.

Jod*_*ins 5

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

除非在该线程中创建了MOC,否则不得在线程中使用MOC.

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

dispatch_queue_t queue = dispatch_queue_create("setup_cell", NULL);
Run Code Online (Sandbox Code Playgroud)

然后在那个区块中,你使用的是那里没有创建的MOC ......

Entry *entry = (Entry *)[customStore.context objectWithID:objectID];
Run Code Online (Sandbox Code Playgroud)

如果您想使用MOC,您必须遵守规则.我将总结规则#1,因为它有几个条款.

  • 如果您使用MOC创建NSConfinementConcurrencyType,则无法调用performBlock该上下文.您必须仅在创建它的线程中使用它.

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

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

编辑

您的商品不同步.您应该只依靠数据实际告诉您的内容.显然,您依靠self.cellInfo.numberOfMediaItems的计数,但它与您的实际数据不同步.

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

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