ios - NSFetchRequest Hangs -
i'm having trouble app hanging on nsfetchrequest. i've been reading quite few hours. there apparently threading issue going on, can't figure out how fix it.
i'm downloading json object server, parsing , storing in coredata model. occurs on background thread complete before app hangs. here code occurs:
- (void) populateregistrationlist:(nsstring *) list script:(nsstring *)script { nsurl *url = [nsurl urlwithstring:[primary_url stringbyappendingstring:script]]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; nsurlsessionconfiguration *configuration = [nsurlsessionconfiguration ephemeralsessionconfiguration]; nsurlsession *session = [nsurlsession sessionwithconfiguration:configuration]; nsurlsessiondownloadtask *task = [session downloadtaskwithrequest:request completionhandler:^(nsurl *localfile, nsurlresponse *response, nserror *error) { if (!error) { nsarray *jobj = [nsjsonserialization jsonobjectwithdata:[nsdata datawithcontentsofurl:localfile] options:kniloptions error:nil]; // make sure result successful if (![[jobj valueforkey:@"result"] isequaltostring:@"success"]) { return; } // context pointer database model appdelegate* appdelegate = [uiapplication sharedapplication].delegate; self.managedobjectcontext = appdelegate.managedobjectcontext; // clear out data previous downloads [self dumptable:list]; nsarray *jarr = (nsarray *) [jobj valueforkey:@"message"]; (int i=0; i<[jarr count]; i++) { nsdictionary *dict = [jarr objectatindex:i]; [self committocoredata:dict]; nserror *error; if (![self.managedobjectcontext save:&error]) nslog(@"whoops, couldn't save: %@", [error localizeddescription]); } // set user default yes tell registrationtwoviewcontroller done [[nsuserdefaults standarduserdefaults] setbool:yes forkey:registration_lists_retrieved]; [[nsuserdefaults standarduserdefaults] synchronize]; } }]; [task resume]; }
subsequently, in main thread, execute fetch request access data this:
@implementation choosesupergroupviewcontroller - (void)viewdidload { [super viewdidload]; // context pointer database model appdelegate* appdelegate = [uiapplication sharedapplication].delegate; self.managedobjectcontext = appdelegate.managedobjectcontext; nslog(@"about fetched objects"); [self.managedobjectcontext performblockandwait:^{ nsfetchrequest *fetchrequest = [[nsfetchrequest alloc] initwithentityname:@"supergroups"]; nserror *error; self.fetchedobjects = [self.managedobjectcontext executefetchrequest:fetchrequest error:&error]; nslog(@"done fetch request"); }]; }
unfortunately, hangs on self.fetchedobjects
line. realize using 2 different threads, know background thread has completed before attempt fetch request. why have concern myself thread @ point? don't see how race condition can occur.
what do fix this? can force fetch request run on same background thread somehow? of posts , articles have read on seem way complicated or don't address threading issue @ all. i'm stuck , don't know else do.
any appreciated. thanks.
this appdelegate:
- (nsmanagedobjectcontext *) managedobjectcontext { if (_managedobjectcontext != nil) { return _managedobjectcontext; } nspersistentstorecoordinator *coordinator = [self persistentstorecoordinator]; if (coordinator != nil) { _managedobjectcontext = [[nsmanagedobjectcontext alloc] initwithconcurrencytype:nsprivatequeueconcurrencytype]; [_managedobjectcontext setpersistentstorecoordinator: coordinator]; } return _managedobjectcontext; } - (nsmanagedobjectmodel *)managedobjectmodel { if (_managedobjectmodel != nil) { return _managedobjectmodel; } _managedobjectmodel = [nsmanagedobjectmodel mergedmodelfrombundles:nil]; return _managedobjectmodel; } - (nspersistentstorecoordinator *)persistentstorecoordinator { if (_persistentstorecoordinator != nil) { return _persistentstorecoordinator; } nsurl *storeurl = [nsurl fileurlwithpath: [[self applicationdocumentsdirectory] stringbyappendingpathcomponent: @"phonebook.sqlite"]]; nserror *error = nil; _persistentstorecoordinator = [[nspersistentstorecoordinator alloc] initwithmanagedobjectmodel:[self managedobjectmodel]]; if(![_persistentstorecoordinator addpersistentstorewithtype:nssqlitestoretype configuration:nil url:storeurl options:nil error:&error]) { /*error store creation should handled in here*/ } return _persistentstorecoordinator; }
it doesn't matter background thread has completed, problem can't safely use same managed object context on multiple threads without ensuring synchronization-- possibly using gcd calls dispatch_async
preferably using core data's built-in synchronization system. don't know why it's failing in case, you're violating major rule of safe core data usage, bad results expected.
to use core data's built-in syncing, create context using nsmainqueueconcurrencytype
or nsprivatequeueconcurrencytype
. then, whenever use context (or objects have fetched context), put code inside performblock
or performblockandwait
call. guarantee synchronous access regardless of number of threads or queues.
alternately, create new managed object context background thread. there's no reason not have more one. work on separate context, , listen nsmanagedobjectcontextdidsavenotification
on main thread merge in new changes.
but whatever do, don't use same context on multiple threads without adequate precautions. when works, it's chance. it'll fail eventually.
Comments
Post a Comment