2011-08-16 12 views
6

मैं (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]; 
      } 
     }]; 

मेरा प्रश्न इस प्रकार है - achievementsDictionary वस्तु प्रकार के किसी भी ताले के बिना, पूरा होने हैंडलर में संशोधित किया जा रहा है। क्या यह अनुमति है क्योंकि पूरा करने वाले हैंडलर काम का एक ब्लॉक है जिसे मुख्य थ्रेड पर इकाई के रूप में निष्पादित करने के लिए आईओएस द्वारा गारंटी दी जाएगी? और कभी थ्रेड सुरक्षा मुद्दों में भाग नहीं? हैंडलर में फिर

@property (retain) NSMutableDictionary* earnedAchievementCache; // note this is atomic 

:

एक और एप्पल नमूना कोड (GKTapper) में, इस भाग को अलग ढंग से नियंत्रित किया जाता है

[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error) 
     { 
      if(error == NULL) 
      { 
       NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]]; 
       for (GKAchievement* score in scores) 
       { 
        [tempCache setObject: score forKey: score.identifier]; 
       } 
       self.earnedAchievementCache= tempCache; 
      } 
     }]; 

तो क्यों अलग शैली है, और एक तरह से अधिक सही है इसके अलावा?

उत्तर

2

क्या यह अनुमति है क्योंकि पूरा करने वाले हैंडलर काम का एक ब्लॉक है जिसे मुख्य थ्रेड पर इकाई के रूप में निष्पादित करने के लिए आईओएस द्वारा गारंटी दी जाएगी? और कभी थ्रेड सुरक्षा मुद्दों में भाग नहीं?

यह निश्चित रूप से यहां मामला नहीं है। -loadAchievementsWithCompletionHandler: के लिए प्रलेखन स्पष्ट रूप से चेतावनी देता है कि पूरा होने वाले हैंडलर को आपके द्वारा लोड शुरू करने के अलावा किसी अन्य धागे पर बुलाया जा सकता है।

ऐप्पल की "थ्रेडिंग प्रोग्रामिंग गाइड" NSMutableDictionary को थ्रेड-असुरक्षित वर्गों के बीच वर्गीकृत करती है, लेकिन इसके साथ योग्यता प्राप्त होती है, "ज्यादातर मामलों में, आप इन कक्षाओं को किसी भी थ्रेड से तब तक उपयोग कर सकते हैं जब तक आप उन्हें एक ही समय में केवल एक थ्रेड से उपयोग करते हैं। "

तो, यदि दोनों ऐप्स इस प्रकार डिज़ाइन किए गए हैं कि उपलब्धि कैश के साथ कुछ भी काम नहीं करेगा जब तक कार्यकर्ता कार्य इसे अपडेट करना समाप्त नहीं कर लेता है, तो कोई सिंक्रनाइज़ेशन आवश्यक नहीं होगा। यह एकमात्र तरीका है जिसमें मैं पहला उदाहरण सुरक्षित होने के रूप में देख सकता हूं, और यह एक कमजोर सुरक्षा है।

बाद वाला उदाहरण ऐसा लगता है कि यह पुराने कैश और नए कैश के बीच स्विचरू बनाने के लिए परमाणु संपत्ति समर्थन पर निर्भर है। यह सुरक्षित होना चाहिए, बशर्ते संपत्ति के लिए सभी पहुंच सीधे आईवर पहुंच के बजाय अपने एक्सेसर्स के माध्यम से हो। ऐसा इसलिए है क्योंकि एक्सेसर्स एक-दूसरे के संबंध में सिंक्रनाइज़ होते हैं, इसलिए आपको आधा सेट मान देखने का जोखिम नहीं होता है। इसके अलावा, गेटर वापस लौटा रहता है और वापस लौटाता है, ताकि पुराना संस्करण वाला कोड क्रैश किए बिना इसके साथ काम करने में सक्षम हो क्योंकि इसे इसके काम के बीच में रिलीज़ किया गया था। एक nonatomic गेटर बस ऑब्जेक्ट सीधे देता है, जिसका मतलब है कि यह आपके कोड के नीचे से हटा दिया जा सकता है अगर उस संपत्ति के लिए एक नया धागा किसी अन्य धागे द्वारा सेट किया गया था। डायरेक्ट इवर एक्सेस एक ही समस्या में चलाया जा सकता है।

मैं कहूंगा कि बाद का उदाहरण सही और सुरुचिपूर्ण दोनों है, हालांकि शायद एक टिप्पणी के बिना थोड़ी अधिक सूक्ष्म सूक्ष्मता बताती है कि संपत्ति की परमाणु कितनी महत्वपूर्ण है।

+0

धन्यवाद जेरेमी। मैं आम तौर पर ब्लॉक समापन हैंडलर के बारे में भी पूछताछ कर रहा था। यदि प्रलेखन स्पष्ट रूप से कहता है कि पूरा करने वाले हैंडलर कहां कहलाता है, तो क्या यह मानना ​​सुरक्षित है कि इसे मुख्य धागे में नहीं कहा जाता है? यदि इसे मुख्य कतार से बुलाया जाना है, तो थ्रेड सुरक्षा के बारे में चिंता किए बिना अंदर कुछ भी करना सुरक्षित है (मान लीजिए कि सभी एक्सेस मुख्य धागे या शिकायत हैंडलर मुख्य कतार पर बुलाए गए हैं)। –

+0

यदि यह निर्दिष्ट नहीं करता है कि आपका ब्लॉक मुख्य कतार/थ्रेड पर कॉल किया जाएगा, तो आपको यह सुनिश्चित करने के लिए अपने स्वयं के उपाय करना होगा, यदि आपको यही चाहिए। इसे वास्तव में मुख्य धागे पर बुलाया जा सकता है, लेकिन उस बिंदु पर, यह तथ्य एक कार्यान्वयन विस्तार है, एपीआई अनुबंध का हिस्सा नहीं है, और चेतावनी के बिना बदल सकता है। यदि इसे मुख्य कतार से बुलाया जाता है, तो आप इसका पूरा लाभ ले सकते हैं। –

+0

तब एक आखिरी सवाल - यदि मैं dispatch_async (dispatch_get_main_queue(),^{(GKAchievement * उपलब्धियों में उपलब्धि) के लिए पहला पूरा करने वाला हैंडलर बदलता हूं [achievementsDictionary setObject: उपलब्धि के लिए उपलब्धि: उपलब्धि। पहचानकर्ता];});) यह होगा कोड थ्रेडसेफ भी हो सकता है? मुझे इस बारे में कुछ याद रखना याद नहीं है .. –