2012-07-22 14 views
10

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

__weak Cell *weakSelf = self; 
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
     UIImage *image = /* render some image */ 
     /* what if by the time I get here self no longer exists? */ 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      [weakSelf setImageViewImage:image]; 
     }]; 
    }]; 
    [self.renderQueue addOperation:op]; 

मेरे सवाल तो, है, मान लें कि उस समय तक छवि प्रतिपादन खत्म और उस लाइन वापस (यह, पुनः आवंटित की जाती किया गया है संभवतः सेल पुन: उपयोग, जो औपचारिक रूप देने के लिए थोड़ा मुश्किल है की वजह से) आता है, Cell ऑब्जेक्ट अब मौजूद नहीं हैं। जब मैं [weakSelf setImageViewImage:] तक पहुंचने के लिए जाता हूं, तो क्या यह EXC_BAD_ACCESS त्रुटि का कारण बनता है?

वर्तमान में मैं यह पता लगाने की कोशिश कर रहा हूं कि मेरी समस्या का कारण क्या है, और मुझे लगता है कि इसका इसके साथ कुछ संबंध हो सकता है।

+0

सेल renderQueue के लिए एक मजबूत रेफरी है? क्या किसी और के पास क्यूई को प्रस्तुत करने के लिए एक मजबूत रेफरी है? यदि आप EXC_BAD_ACCESS के कारण का पता लगाना चाहते हैं, तो एक इंटरैक्टिव डीबगर या इंस्ट्रूमेंट्स का उपयोग करें। – outis

+0

कमजोर संदर्भ यहां असफल होना चाहिए। एआरसी मानते हुए, 'ओपी' इस कोड में जो भी तरीका है, उसके अंत में जारी किया जा रहा है, (इसे ऑपरेशन कतार द्वारा भी बनाए रखा/जारी किया गया है, लेकिन इस समय यह अप्रासंगिक है)। यदि आप ब्लॉक को रिहा करने के लिए 'स्वयं' के 'डेलोक' पर भरोसा कर रहे थे, तो केवल एक बरकरार चक्र होगा, यानी, आप इसे एक ivar में संग्रहीत कर रहे थे। यहां मामला नहीं है, और इसलिए आपको 'स्वयं' बनाए रखने वाले ब्लॉक के बारे में चिंता करने की आवश्यकता नहीं है। –

+0

तो ऑपरेशन कतार कब आइटम जारी करती है? निष्पादन पूरा करने के बाद, स्वचालित रूप से? या मुझे मैन्युअल रूप से ब्लॉक जारी करना होगा? मैं एआरसी का उपयोग कर रहा हूँ। – Snowman

उत्तर

18

तो, __weak एक शून्यीकरण को कमजोर संदर्भ है। इसका अर्थ यह है कि आपके ऑपरेशन के दौरान, self वास्तव में हटाया जा सकता है, लेकिन इसके सभी कमजोर संदर्भ (अर्थात् weakSelf) शून्य हो जाएंगे। इसका मतलब है कि [weakSelf setImageViewImage:image] सिर्फ nil पर एक संदेश भेज रहा है, जो सुरक्षित है; या, कम से कम, यह EXC_BAD_ACCESS का कारण नहीं बनना चाहिए। (संयोग से, अगर आप weakSelf योग्य था __unsafe_unretained के रूप में, आप एक मुक्त कर दिया वस्तु को संदेश भेजने खत्म हो सकता है।)

तो, मुझे शक है कि एक __weak संदर्भ को कोई संदेश भेजने एक दुर्घटना हो रही है।

__weak Cell *weakSelf = self; 

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
    Cell *strongSelf = weakSelf; // object pointers are implicitly __strong 
    // strongSelf will survive the duration of this operation. 
    // carry on. 
}]; 
8

आप कमजोर का उपयोग नहीं करते हैं, तो आप एक बना रहे हैं: क्या आप यह सुनिश्चित करें कि self आपके ऑपरेशन की लंबाई के लिए बचता चाहते हैं, आप ब्लॉक दायरे में कमजोर एक के लिए एक मजबूत संदर्भ प्राप्त कर सकते हैं चक्र बनाए रखें, लेकिन जैसे ही ब्लॉक निष्पादित हो जाते हैं, चक्र टूट जाएगा। मैं शायद यहां कमज़ोर का उपयोग करके परेशान नहीं होगा।

वैसे भी, आप nil पर कोई संदेश भेज सकते हैं, और इसे अनदेखा कर दिया जाएगा। weakSelf चर nil करने के लिए सेट हो जाता है तो अगर क्योंकि Cell वस्तु पुनः आवंटित की जाती है, setImageViewImage: संदेश चुपचाप कुछ भी नहीं होगा। यह दुर्घटनाग्रस्त नहीं होगा।

चूंकि आप सेल पुन: उपयोग का उल्लेख करते हैं, मुझे लगता है कि आपका CellUITableViewCell का उप-वर्ग है। उस स्थिति में, आपके उदाहरण कोड में एक गंभीर समस्या है। UITableViewCell एस आमतौर पर हटाया नहीं जाता है। वे सेल पुन: उपयोग कतार पर डाल दिया। तो आपका weakSelf वैरिएबल शून्य नहीं होगा, क्योंकि कमजोर संदर्भ केवल शून्य हो जाता है जब ऑब्जेक्ट वास्तव में डिलीकेट किया जाता है।

जब तक [weakSelf setImageViewImage:image] लाइन चलाया जाता है, तब तक सेल को आपकी तालिका में एक अलग पंक्ति का प्रतिनिधित्व करने के लिए पुन: उपयोग किया जा सकता है, और आप सेल में गलत छवि डाल रहे हैं। आप Cell कक्षा से बाहर अपनी छवि-प्रतिपादन कोड बढ़ना चाहिए, अपने तालिका दृश्य के डेटा स्रोत वर्ग में:

- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    Cell *cell = // get a cell... 

    [self startLoadingImageForIndexPath:indexPath]; 
    return cell; 
} 

- (void)startLoadingImageForIndexPath:(NSIndexPath *)indexPath { 
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
     UIImage *image = [self renderImageForIndexPath:indexPath]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      Cell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; 
      [cell setImageViewImage:image]; 
     }); 
    }]; 
    [self.renderQueue addOperation:op]; 
} 
+0

रुको, आपका क्या मतलब है कि स्वयं ऑपरेशन कतार को बरकरार नहीं रखता है? यह मेरी कक्षा में एक मजबूत संपत्ति है। या आप कुछ और मतलब था? – Snowman

+0

ओह। आप सही हैं, यह renderQueue बनाए रखता है। लेकिन यह एक अल्पकालिक चक्र है, जैसे ही ब्लॉक निष्पादित हो जाते हैं, स्वचालित रूप से टूट जाते हैं। –

+0

क्या होगा यदि मैं अपने स्वयं के शब्दकोश में ब्लॉक ऑपरेशंस को संग्रहीत कर रहा हूं जो डेटा स्रोत द्वारा दृढ़ता से आयोजित किया जाता है, ताकि मैं आवश्यकतानुसार संचालन को पुनर्प्राप्त और रद्द कर सकूं। यह चीजों को कैसे बदल देगा? – Snowman

संबंधित मुद्दे