我有一個類「廣告」在這裏我設置一個靜態變量,我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