ios - Thread safe and "Collection was mutated while being enumerated" -


i have class "ad" set static variable inside ad.m :

static nsdictionary *citiesdict = nil; // class variable  

and in same file have implemented class method load plist file of name of cities index numbers if it's not loaded , convert number value passed paramater name of city :

+(nsstring *) cityfromnumbervalue:(nsstring *)citynumbervalue {        // load cities plist file named "cities" if it's not loaded     if (!citiesdict)     {           nsstring *path = [[nsbundle mainbundle] pathforresource:@"cities" oftype:@"plist"];         citiesdict = [[nsdictionary alloc ]initwithcontentsoffile:path];        nslog(@"loading plist");      }  nslog(@"will return value"); nsarray *temp = [ citiesdict allkeysforobject:citynumbervalue];   nsstring *key = [temp lastobject];  return key ; } 

and in same file have implement init method convert dictionary ad object uses class method +cityfromnumbervalue:citynumbervalue :

-(id) initwithdictionary: (nsdictionary *) dictionay {     self = [super init];     if (self)     {     // convert number name of city     self.departurecity= [ad cityfromnumbervalue:[dictionay objectforkey:@"ad_villedepart"]];      self.arrivalcity=   [ad cityfromnumbervalue:[dictionay objectforkey:@"ad_villearrivee"]];      } return self; } 

and have inside same file method fetch ads web service calls method +cityfromnumbervalue:citynumbervalue: inside loop :

+(nsdictionary *) fetchadofpage : (nsinteger) page perpage : (nsinteger) perpage {     nsmutablearray *  adsarray = [[nsmutablearray alloc] init];    ......      nsmutablearray *array = [nsarray arraywithcontentsofurl:url];  // convert new fetchted dictionnaries of ads ad objects  (nsmutabledictionary *dictad in array)  {    // convertion using designated initializer      ad *ad = [[ad alloc]initwithdictionary:dictad];      [adsarray addobject:ad];       }       ....     return dictfinal ; } 

and somewhere else mu controller call fetch methode :

 // request on async thread         dispatch_queue_t fetchq = dispatch_get_global_queue(dispatch_queue_priority_default, 0);         dispatch_async(fetchq, ^{              nsdictionary * dict = [ad fetchadofpage:currentpage perpage:kadsperpage];              dispatch_sync(dispatch_get_main_queue(), ^{                 .....             });         });          dispatch_release(fetchq); 

now problem last time when run app inside simulator got error "collection mutated while being enumerated" , points line :

 nsarray *temp = [ citiesdict allkeysforobject:citynumbervalue]; 

but got error first time , didn't before , use same code more 3 months , ok , , can't reproduce same error again ! after putting nslog see happen :

2013-05-21 19:39:20.141 myapp[744:3b03] loading plist 2013-05-21 19:39:20.151 myapp[744:6303] return value 2013-05-21 19:39:20.151 myapp[744:3b03] return value 2013-05-21 19:39:20.152 myapp[744:6303] return value 2013-05-21 19:39:20.153 myapp[744:6303] return value 2013-05-21 19:39:20.154 myapp[744:6303] return value 2013-05-21 19:39:20.153 myapp[744:3b03] return value 2013-05-21 19:39:20.155 myapp[744:6303] return value 

but 1 time got :

2013-05-21 19:39:20.141 myapp[744:3b03] loading plist 2013-05-21 19:39:20.142 myapp[744:6303] loading plist 2013-05-21 19:39:20.151 myapp[744:6303] return value 2013-05-21 19:39:20.151 myapp[744:3b03] return value 2013-05-21 19:39:20.152 myapp[744:6303] return value 2013-05-21 19:39:20.153 myapp[744:6303] return value 2013-05-21 19:39:20.154 myapp[744:6303] return value 2013-05-21 19:39:20.153 myapp[744:3b03] return value 2013-05-21 19:39:20.155 myapp[744:6303] return value 

the app didn't crash there strange "loading plist" twice since have checked using if statement ! guess there 2 threads have entered :

if (!citiesdict) 

at same time , , both of them hav set citiesdict dictionary , since dictionary can used in

 [ citiesdict allkeysforobject:citynumbervalue];  

just after if statement can cause crash "collection mutated while being enumerated" , can real senario ?

since can't reproduce error again wonder if adding :

   @synchronized(citiesdict)     {         citiesdict = [[nsdictionary alloc ]initwithcontentsoffile:path];         nslog(@"loading plist");     } 

can fix issue ? have suggestion better implement safer implementation , how avoid in general "collection mutated while being enumerated" error when obliged work same array different threads , , can reading content of array different threads causes problem or problem when writing @ same time ? thank in advance

when working static objects, best practice use dispatch_once, ensure code executed once, giving complete thread safety

it's practice have getter method static objects

+ (nsdictionary *)getcitiesdict {     static dispatch_once_t pred;     static nsdictionary *citiesdict = nil;      dispatch_once(&pred, ^{         nsstring *path = [[nsbundle mainbundle] pathforresource:@"cities" oftype:@"plist"];          citiesdict = [[nsdictionary alloc ]initwithcontentsoffile:path];     });      return citiesdict; } 

to access it, go this

[[ownerclass getcitiesdict] valueforkey:@"key"]; // ownerclass name of class defined 

Comments

Popular posts from this blog

blackberry 10 - how to add multiple markers on the google map just by url? -

php - guestbook returning database data to flash -

delphi - Dynamic file type icon -