ios - Core Data Lazy Loading with NSPrivateQueueConcurrencyType and custom setter not working -


problem: fetching managed object using background thread not lazy load nsmanaged object relationship correctly when nsmanaged object related has custom setter. doing fetch on main thread main concurrency type works without problem. why this?

work around: if create custom getter on relationship object , check nil, can force nsmanaged object load calling other variables don't have custom setter methods.

background core data layout pretty simple. have game managed object , turn managed object. turn object 1 one relationship game object. fetch game object in order access turn object. turnimp , gameimp implementation classes inherit game , turn object don't put getter/setter methods in auto generated code.

code

the fetch

// //stick command on background // dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), ^ {     //     //load game      //     appdelegate *appdelegate = [[uiapplication sharedapplication] delegate];     coredatahelper *coredatahelper = appdelegate.coredatahelper;     nsmanagedobjectcontext *childmoc = [coredatahelper createchildmanagedobjectcontext];      //the request     nsfetchrequest *fetchrequest = [nsfetchrequest new];      //the object entity want     nsentitydescription *entity = [nsentitydescription entityforname:gameimp_game inmanagedobjectcontext:childmoc];     [fetchrequest setentity:entity];      //the predicate rules,     nspredicate *predicate = [nspredicate predicatewithformat:@"gameid == %@", @"1404110671234567"];     [fetchrequest setpredicate:predicate];      //the sorting rules     nssortdescriptor *sortdescriptor = [[nssortdescriptor alloc]initwithkey:gameimp_object_id ascending:yes];     nsarray *sortdescriptors = [[nsarray alloc]initwithobjects:sortdescriptor, nil];     [fetchrequest setsortdescriptors:sortdescriptors];      //fetch results     nsfetchedresultscontroller *resultscontroller = [[nsfetchedresultscontroller alloc] initwithfetchrequest:fetchrequest managedobjectcontext:childmoc sectionnamekeypath:nil cachename:nil];     nserror *error;     bool success = [resultscontroller performfetch:&error];     gameimp *game;     if (success) {         game = [resultscontroller.fetchedobjects objectatindex:0];     } else {         nslog(@"unable game. error: %@", error);     }     turnimp *turnimp = game.turn;      //issue here!!! should 3, instead 0 because lastroundreward nil.     int lastroundreward = [turnimp.lastroundreward intvalue];      //work around, call custom getter method. 3 returned.     lastroundreward = [turnimp getlastroundreward];  } 

this childmoc creation

-(nsmanagedobjectcontext*) createchildmanagedobjectcontext {    nsmanagedobjectcontext *childmoc = [[nsmanagedobjectcontext alloc]    initwithconcurrencytype:nsprivatequeueconcurrencytype];    childmoc.parentcontext = self.mainmanagedobjectcontext;     return childmoc; } 

turnimp header

@interface turnimp : turn  @property(atomic) bool isvalid; - (void) setlastroundreward: (int) lastroundreward; - (int) getlastroundreward; @end 

turnimp m

@implementation turnimp  @synthesize isvalid; @synthesize lastroundreward = _lastroundreward;  /**  * set last round reward  * @param -  * @return -  */ - (void) setlastroundreward: (int) lastroundreward {     _lastroundreward = [nsnumber numberwithint:lastroundreward]; }  /**  * int value of lastroundreward */ - (int) getlastroundreward {     //note - hack! lazy loading not working, try member     if (self.lastroundreward == nil) {         //force load         nsstring *objectid = self.objectid;     }     return [self.lastroundreward intvalue]; } 

change childmoc mainmoc , works. mainmoc code

 //create main moc  _mainmanagedobjectcontext = [[nsmanagedobjectcontext alloc] initwithconcurrencytype:nsmainqueueconcurrencytype]; 

more after fixed concurrency issue

[childmoc performblock:^{          // execute fetch on childmoc , other work.         nserror *error;         nsarray *results = [childmoc executefetchrequest:fetchrequest error:&error];         if (results == nil) {             // handle error         } else if (results.count == 1) {             gameimp *game = [results firstobject];             turnimp *turnimp = game.turn;              //issue here!!! should 3, instead 0 because lastroundreward nil.             int lastroundreward = [turnimp.lastroundreward intvalue];              //work around, call variable objectid (not same objectid)             nsstring *objectid = turnimp.objectid;             //not it's 3...             lastroundreward = [turnimp.lastroundreward intvalue];          }     }]; 

work around

i removed following turnimp , works expected relationships.

@synthesize lastroundreward = _lastroundreward; 

first, have confess have no idea problem statement means - lazy loading of relationship supposed anyway?

however, quick glance @ code reveals creating moc nsprivatequeueconcurrencytype yet not wrapping use inside appropriate performblock invocation.

when violate core data concurrency guidelines, playing in dangerous waters , undefined behavior.

also, why create instance of nsfetchedresultscontroller perform fetch? that's overkill. use fetch request. so...

[childmoc performblock:^{     // execute fetch on childmoc , other work.     nserror *error;     nsarray *results = [childmoc executefetchrequest:fetchrequest error:&error];     if (result == nil) {         // handle error     } else if (results.count == 1) {         gameimp *game = [results firstobject];         turnimp *turnimp = game.turn;         int lastroundreward = [turn2.lastroundreward intvalue];     } }]; 

Comments

Popular posts from this blog

php - Invalid Cofiguration - yii\base\InvalidConfigException - Yii2 -

How to show in django cms breadcrumbs full path? -

ruby on rails - npm error: tunneling socket could not be established, cause=connect ETIMEDOUT -