在枚举时保存数组

时间:2014-12-17 16:43:33

标签: ios objective-c nsuserdefaults

我希望每次用户与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;
            }
        }

    }
 });
}

3 个答案:

答案 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的文档:

https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_queue_create

答案 2 :(得分:0)

当您在后台队列中使用数组时,请在主线程上分离该块以确保您按照特定顺序执行所有操作。

相关问题