MagicalRecord: How to save imported data in background

谁说我不能喝 提交于 2019-12-10 20:17:22

问题


I'm trying to import data into Core Data and save it in a background thread with MagicalRecord.

I'm basically trying to do this:

__block User *user = nil;
[MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext)
{
     user = [User MR_findFirstOrCreateByAttribute:@"userId" withValue:userId inContext:localContext];
     [user MR_importValuesForKeysWithObject:responseObject];
}];

[User setCurrentUser:user];

User is correct when I'm inside the block. After the block is completed user is a NSManagedObject object, but doesn't have any attributes set.

This, on the other hand, works:

OEUser *user = [OEUser MR_findFirstOrCreateByAttribute:@"userId" withValue:userId];                               
[user MR_importValuesForKeysWithObject:responseObject];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
[User setCurrentUser:user];

But I want to save it in the background.


I also tried this to no avail.

User *user = [User MR_findFirstOrCreateByAttribute:@"userId" withValue:userId];
[MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext)
{
     User *localUser = [user MR_inContext:localContext];
     [user MR_importValuesForKeysWithObject:responseObject];
}];

[User setCurrentUser:user];

The problem here seems to be that [user MR_inContext:localContext] returns nil.

I'm pretty new to Core Data, so bear with me if I'm missing something obvious.


回答1:


When you use the *Wait method you are not gaining any asynchronicity and you will still be blocking your main thread during the import. You should indeed be using the block methods but this to ensure that any Core Data operations are performed on the correct thread (the thread the NSManagedObjectContext was created on).

When you use saveWithBlockAndWait: MagicalRecord creates a new context on a background thread to perform it's work on. This newly created context is then yielded to your block and lives only for the scope of the block. You can not pass NSManagedObject's between contexts so you should not be trying to capture the user from outside the block.

I can imagine the second example will only actually be failing in the case of creating a new User because you call MR_findFirstOrCreateByAttribute:withValue: which will create a new NSManagedObject in memory but this is not persisted to the store therefore inside the saveWithBlockAndWait: there is no User to pull from the store.

The correct way would be

[MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
  User *localUser = [User MR_findFirstOrCreateByAttribute:@"userId" 
                                                withValue:userId     
                                                inContext:localContext];
  [user MR_importValuesForKeysWithObject:responseObject];
}];

User *user = [User MR_findFirstByAttribute:@"userId" withValue:userId];

[User setCurrentUser:user];

As mentioned this will block the main thread so you may want to consider moving to saveWithBlock:completion: instead which will perform the work in the background and not block the current thread.

Even better I would consider not holding onto an actual User object but instead hold onto the userId, which will safe you headaches down the line when people start accessing the currentUser from all kinds of threads



来源:https://stackoverflow.com/questions/23768124/magicalrecord-how-to-save-imported-data-in-background

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