CoreData concurrency

五迷三道 提交于 2019-12-13 05:04:29

问题


I have an issue with CoreData persistance (MagicalRecord 2.2, iOS 7.x) Main object can be created and used on any thread:

- (Collection *)collection {

    if (!_collection) {
        [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
            _collection = [Collection MR_createInContext:localContext];
            _collection.creationDate = [NSDate date];
            _collection.collectionDescription = @"";
            _collection.name = [CollectionHelper getNameForUnnamedCollection];
        }];
    }

    return _collection;
}

In any place of code i can start adding resources to this collection in background thread:

    if (self.photoSavingBlocksCount == 0) {
        [self beginPhotoSaving];
    }
    self.photoSavingBlocksCount++;
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    Collection *localCollection = [self.collection MR_inContext:localContext];
    [localCollection addNewResourceForImage:image thumb:thumb gallery:gallery type:RESOURCE_TYPE_IMAGE];
} completion:^(BOOL success, NSError *error) {
    self.photoSavingBlocksCount--;
    if (self.photoSavingBlocksCount == 0) {
        [self endPhotoSaving];
    }
}];

This code marks collection and its resources as uploaded to server:

- (BOOL)markCollectionAsUploaded:(Collection *)collection {
    [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
        Collection *localCollection = [collection MR_inContext:localContext];
        localCollection.uploaded = @YES;
        localCollection.uploadDate = [NSDate date];
    }];
    return YES;
}

This code works fine, but if i edit collection before this, then this code will fail and collection won't be saved as uploaded! In other words on next fetch i will get collection.uploaded == @NO!

This code saves edited collection

    [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {

            Collection *localCollection = [self.collection MR_inContext:localContext];

            NSSet *set = [NSSet setWithArray:self.deletedResources];

            localCollection.uploaded = @NO;
            localCollection.name = ([fieldName.text length] == 0 || [[fieldName.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0)
            ? [CollectionHelper getNameForUnnamedCollection]
            : fieldName.text;
            localCollection.collectionDescription = [fieldDescription.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

            for (Resource *resource in set) {
                Resource *localResource = [resource MR_inContext:localContext];
                [CollectionHelper removeResourceFiles:resource];
                [localResource MR_deleteEntity];
            }
        }];

In logs i see same picture for every context saving:

-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x196e2ee0) → Saving <NSManagedObjectContext (0x196e2ee0): *** UNNAMED ***> on *** BACKGROUND THREAD ***
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x196e2ee0) → Save Parents? 1
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x196e2ee0) → Save Synchronously? 1
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x17d83e30) → Saving <NSManagedObjectContext (0x17d83e30): *** BACKGROUND SAVING (ROOT) ***> on *** BACKGROUND THREAD ***
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x17d83e30) → Save Parents? 1
-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x17d83e30) → Save Synchronously? 1

Could somebody show me a proper way to manage CoreData objects for my situation? I will appreciate any help.


回答1:


In your first block of code, you want to do this instead:

- (Collection *)collection {

    if (!_collection) {
        [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
            _collection = [Collection MR_createInContext:localContext];
            _collection.creationDate = [NSDate date];
            _collection.collectionDescription = @"";
            _collection.name = [CollectionHelper getNameForUnnamedCollection];
        }];
    }
    _collection = [_collection MR_inContext:self.context];
    return _collection;
}

When you return from the save block, the localContext is discarded from memory, and your object will be unable to save. To avoid this problem, you should then refresh this new object into your local, longer lived context. You could avoid this pattern altogether by not using a block and save directly into your longer lived context.

And, honestly, I didn't read the rest of the question, because this should be cleared up first to avoid obscure crashes down the line...



来源:https://stackoverflow.com/questions/24171213/coredata-concurrency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!