我希望每次用户与tableview中的行交互时将数组保存到NSUserDefaults
(例如删除它们)
但是,我遇到了以下问题:
想象一下以下用例:
User deletes row -> row is deleted from datasource, datasource is saved to disk
User deletes another row -> row is deleted from datasource, app crashes because datasource of the first action is still being enumerated
我该如何解决这个问题?应用程序向用户提供实时反馈非常重要,因此不希望用户必须等待的任何检查。
这是我用来将数据源保存到磁盘的代码:
if(allowSavePaymentArray){
dispatch_async(kAsyncQueue, ^{
allowSavePaymentArray = NO;
__block int loopCount = 0;
NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:dataSourceArray.count];
for (NSMutableDictionary *object in dataSourceArray) {
// PFFile isn't easy to encode, but UIImage is, so whenever we encounter a PFFile, we convert it to UIImage
id imageFile = [payment objectForKey:@"img"];
if([imageFile isKindOfClass:[PFFile class]]){
[imageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
[payment setObject:image forKey:@"img"]; // the PFFile is now replaced for an UIImage
NSData *paymentEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:payment];
[archiveArray addObject:paymentEncodedObject];
loopCount++;
if(loopCount == [paymentArray count]){ // when done looping, save it all
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:archiveArray forKey:@"payments"];
allowSavePaymentArray = YES;
}
}
}];
} else {
loopCount++;
NSData *paymentEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:payment];
[archiveArray addObject:paymentEncodedObject];
if(loopCount == [paymentArray count]){ // when done looping
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:archiveArray forKey:@"payments"];
allowSavePaymentArray =YES;
}
}
}
});
}
答案 0 :(得分:1)
您的问题是您在后台线程上使用快速枚举,并且您可能会在主(或其他)线程上修改后台线程上枚举的数组。
修复很简单。创建数组的副本:
__block int loopCount = 0;
NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:dataSourceArray.count];
NSArray *tempArray = [dataSourceArray copy]; // make a copy
for (NSMutableDictionary *object in tempArray) {
答案 1 :(得分:0)
您可以使用串行队列,这将在当时执行一个进程。
dispatch_queue_t kAsyncQueue;
kAsyncQueue = dispatch_queue_create("com.example.MyQueue", NULL);
这里有来自apple的文档:
答案 2 :(得分:0)
当您在后台队列中使用数组时,请在主线程上分离该块以确保您按照特定顺序执行所有操作。