我有一个类“广告”在这里我设置一个静态变量,我Ad.m内“收集了同时列举突变”方法如果没有加载,基本上加载使用其指数的城市名称的plist文件,并最终转化为paramater传递到城市的名称中的数字值:线程安全的,
+(NSString *) cityFromNumberValue:(NSString *)cityNumberValue
{
// load the cities from the plist file named "cities" if it's not already 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 ;
}
,总是在同一个文件我已经实现了一个init方法来将字典转换为广告对象wh ERE它使用类方法+ cityFromNumberValue:cityNumberValue:
-(id) initWithDictionary: (NSDictionary *) dictionay
{
self = [super init];
if (self)
{
// convert the number to name of city
self.departureCity= [Ad cityFromNumberValue:[dictionay objectForKey:@"ad_villedepart"]];
self.arrivalCity= [Ad cityFromNumberValue:[dictionay objectForKey:@"ad_villearrivee"]];
}
return self;
}
而且我也有同样的文件中,从Web服务的地方调用该方法+ cityFromNumberValue获取信息的方法:cityNumberValue:里面一个for循环:
+(NSDictionary *) fetchAdOfPage : (NSInteger) page PerPage : (NSInteger) perPage
{
NSMutableArray * adsArray = [[NSMutableArray alloc] init];
......
NSMutableArray *array = [NSArray arrayWithContentsOfURL:url];
// convert the new fetchted dictionnaries of Ads to an Ad objects
for (NSMutableDictionary *dictAd in array)
{
// convertion using the designated initializer
Ad *ad = [[Ad alloc]initWithDictionary:dictAd];
[adsArray addObject:ad];
}
....
return dictFinal ;
}
和万亩控制器别的地方我把这个取梅索德这样的:
// do 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);
我现在的问题是,上一次当我运行内部应用程序我得到一个错误模拟器“收藏突变而被枚举”,它指向行:
NSArray *temp = [ citiesDict allKeysForObject:cityNumberValue];
,但我得到这个错误是第一次,之前我没有得到它,我用同样的代码超过三个月,一切正常,我甚至不能再次重现相同的错误!把一个NSLog的,看后有什么发生,我总是得到:
2013-05-21 19:39:20.141 myApp[744:3b03] loading plist
2013-05-21 19:39:20.151 myApp[744:6303] will return value
2013-05-21 19:39:20.151 myApp[744:3b03] will return value
2013-05-21 19:39:20.152 myApp[744:6303] will return value
2013-05-21 19:39:20.153 myApp[744:6303] will return value
2013-05-21 19:39:20.154 myApp[744:6303] will return value
2013-05-21 19:39:20.153 myApp[744:3b03] will return value
2013-05-21 19:39:20.155 myApp[744:6303] will return value
,但有一次我得了:
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] will return value
2013-05-21 19:39:20.151 myApp[744:3b03] will return value
2013-05-21 19:39:20.152 myApp[744:6303] will return value
2013-05-21 19:39:20.153 myApp[744:6303] will return value
2013-05-21 19:39:20.154 myApp[744:6303] will return value
2013-05-21 19:39:20.153 myApp[744:3b03] will return value
2013-05-21 19:39:20.155 myApp[744:6303] will return value
应用程序没有崩溃,但有一个奇怪的“装载的plist”两次,因为我使用if语句进行了检查!所以我想这有两个线程都进入:
if (!citiesDict)
在同一时间,然后他们两个甲肝设置citiesDict词典,自本词典可以
[ citiesDict allKeysForObject:cityNumberValue];
只是后使用可能导致崩溃的if语句“Collection被枚举时发生了变化”,这可以成为真正的senario吗?
,因为我不能再重现错误不知是否添加:
@synchronized(citiesDict)
{
citiesDict = [[NSDictionary alloc ]initWithContentsOfFile:path];
NSLog(@"loading plist");
}
可以解决这个问题?你有什么建议可以更好地实现一个更安全的实现,以及当我们必须从不同的线程处理同一个数组,并且可以从数组中读取数组的内容时,我们通常如何避免“集合在被列举时发生了变化”错误不同的线程会导致问题,或者问题出在同一时间写入?预先感谢您的帮助
谢谢你的回答,但是我应该在我加载plist之前测试它是否已经设置避免我一直调用getter来加载它?或者我会通过执行'if(!citiesDict)'来检查我将从哪里调用getter? – iOSGeek
不需要检查。 dispatch_once块在应用程序的整个生命周期中只执行一次,这意味着citiesDict只会创建一次,并且会在活着并准备就绪之后。只要打电话给[self getCitiesDict],你就会好起来 – Ismael
再次感谢你的回放,就像你不介意最后一个问题一样,实际上还有其他一些处理城市的类方法,他们需要同一个字典和他们测试它是否没有加载,他们从plist中加载它们,并且他们可以在同一时间执行: 'if(!citiesDict) { NSString * path = [[NSBundle mainBundle] pathForResource:@“cities “ofType:@”plist“]; citiesDict = [[NSDictionary alloc] initWithContentsOfFile:path]; }' 是否安全,在使用dispatch_once实现getter解决方案后可否面临任何问题? – iOSGeek