我有一個關於蘋果(從的GameKit編程指南)下面的代碼示例的線程安全問題修改可變對象在完成處理
這是加載從遊戲中心成就和本地保存:
步驟1)添加一個可變的字典屬性到你的類,報告成就。這本詞典存儲了成就對象的集合。
@property(nonatomic, retain) NSMutableDictionary *achievementsDictionary;
步驟2)初始化成績字典。
achievementsDictionary = [[NSMutableDictionary alloc] init];
步驟3)修改加載加載成就數據的代碼,將成就對象添加到字典中。
{
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
{
if (error == nil)
{
for (GKAchievement* achievement in achievements)
[achievementsDictionary setObject: achievement forKey: achievement.identifier];
}
}];
我的問題如下 - 在完成處理程序中正在修改achievementDictionary對象,沒有任何排序鎖定。這是否允許,因爲完成處理程序是一個工作塊,將由iOS保證在主線程上作爲單元執行?永遠不會遇到線程安全問題?在處理
@property (retain) NSMutableDictionary* earnedAchievementCache; // note this is atomic
然後:
在另一個蘋果的示例代碼(GKTapper),這部分的處理方式不同
那麼,爲什麼不同的風格,是一種方式更正確比其他?
謝謝傑里米。一般來說,我也在質疑塊完成處理程序。如果文檔沒有明確說明完成處理程序被調用的位置,那麼可以安全地假設它沒有在主線程中調用?如果指定從主隊列中調用,那麼在不擔心線程安全的情況下(假設所有訪問都來自主線程或主隊列上調用的處理程序處理程序),在內部執行任何操作都是安全的。 –
如果它沒有指定你的塊將在主隊列/線程上被調用,那麼你必須採取自己的措施來確保它是,如果這是你所需要的。它可能實際上在主線程中被調用,但是在那一點上,這個事實是一個實現細節,而不是API合約的一部分,並且可能在沒有警告的情況下改變。如果指定從主隊列中調用,那麼您可以充分利用這一點。 –
最後一個問題 - 如果我改變第一個完成處理程序使用dispatch_async(dispatch_get_main_queue(),^ {for(GKAchievement * achievement in achievement) [achievementDictionary setObject:achievement forKey:achievement.identifier];});) will this代碼也是線程安全的?我記得讀過一些關於這個不安全的東西.. –