2010-05-28 13 views
60

मैं एक आईफोन ऐप पर काम कर रहा हूं जिसमें वेब से ली गई डेटा के साथ एक बहुत बड़ा UITableView है, इसलिए मैं इसकी रचना और उपयोग को अनुकूलित करने की कोशिश कर रहा हूं।आईफोन - dequeueReusableCellWithIdentifier उपयोग

मुझे पता चला कि dequeueReusableCellWithIdentifier बहुत उपयोगी है, लेकिन इसका उपयोग करके कई स्रोत कोड देखने के बाद, मुझे आश्चर्य है कि अगर मैं इस फ़ंक्शन का उपयोग करता हूं तो यह अच्छा है।

यहाँ लोगों को आमतौर पर क्या करना है:

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 

if (cell == nil) { 
    cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"]; 

// Add elements to the cell 
return cell; 

और यहाँ जिस तरह से मैंने किया है:

// The cell row 
NSString identifier = [NSString stringWithFormat:@"Cell %d", indexPath.row]; 

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 

if (cell != nil) 
    return cell; 

cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier]; 
// Add elements to the cell 
return cell; 

अंतर यह है कि लोगों को हर कोशिका के लिए एक ही पहचानकर्ता का उपयोग, इसलिए एक dequeuing है केवल एक नया आवंटित करने से बचाता है।

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

ठीक में मुझे नहीं पता कि कौन सा सबसे अच्छा है, "सामान्य" विधि तालिका के मेमोरी उपयोग को कोशिकाओं की सटीक संख्या तक सीमित करती है, जिससे मैं जिस विधि का उपयोग करता हूं, वह गति का पक्ष लेता है क्योंकि यह सभी गणना करता है कोशिकाएं, लेकिन बड़ी स्मृति खपत का कारण बन सकती हैं (जब तक कि कतार में आंतरिक सीमा न हो)।

क्या मैं इसे इस तरह उपयोग करना गलत हूं? या क्या यह सिर्फ अपनी जरूरतों के आधार पर डेवलपर तक है?

उत्तर

70

dequeueReusableCellWithIdentifier का उद्देश्य कम स्मृति का उपयोग करना है। यदि स्क्रीन 4 या 5 टेबल कोशिकाओं को फिट कर सकती है, तो पुन: उपयोग के साथ आपको तालिका में आवंटित 4 या 5 तालिका कक्षों की आवश्यकता होती है भले ही तालिका में 1000 प्रविष्टियां हों।

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

+0

आप इस तथ्य के बारे में सही हैं कि मेरी विधि के साथ एक सरणी नौकरी कर सकती है। ~ 100 कोशिकाएं एक बार में आवंटित स्मृति की 'बहुत' बड़ी मात्रा का प्रतिनिधित्व करती हैं? – Jukurrpa

+0

ठीक है, मैंने सामान्य विधि के लिए बदल दिया है (जो जटिल है जब एक पंक्ति में कई सबव्यूज़ होते हैं), और कम स्मृति खपत के अलावा, स्क्रॉलिंग समग्र रूप से चिकनी लगती है, मुझे यकीन नहीं है कि क्यों। वैसे भी सलाह के लिए धन्यवाद! – Jukurrpa

+0

@progrmr ... धन्यवाद ... अवधारणा को साफ़ करने के लिए .. यह वास्तव में अच्छा है ... मैं भी वही गलती कर रहा था .. :) –

4

मुझे लगता है कि UITableView को लागू करने के लिए पहला सबसे अच्छा (और जैसा कि आपने सामान्य कहा) तरीका है। आपके दूसरे तरीके से प्रदर्शित होने वाले प्रत्येक नए सेल के लिए आवंटित स्मृति होगी और कोई स्मृति पुन: उपयोग नहीं की जाएगी।

+0

यदि उपयोगकर्ता नीचे स्क्रॉल करता है और फिर बैक अप स्क्रॉल करता है तो अच्छी मेमोरी का पुन: उपयोग किया जाएगा ... या किसी भी समय तालिका दृश्य एक सेल तक पहुंचता है जिसे एक बार छुपाया गया था। – Jukurrpa

+0

निश्चित रूप से, लेकिन प्रत्येक सेल के लिए एक स्मृति पदचिह्न होगा जो कभी प्रदर्शित किया गया था और न केवल वर्तमान में प्रदर्शित 4-5 सेल के लिए। मुझे मानचित्र के लिए एनोटेशन के साथ एक ही समस्या है। निरंतर पहचानकर्ता को स्विच करने से प्रदर्शन की उल्लेखनीय वृद्धि हुई। – AlexVogel

+0

तो मुझे लगता है कि यह मेरे ऊपर है ... क्या सेल के बजाए सेल बनाने के लिए उपयोग किए जाने वाले किसी भी डेटा को कैश करना बेहतर होगा? – Jukurrpa

20

सेल पहचानकर्ता के लिए- पहचानकर्ता के लिए केवल "सेल" का उपयोग करने के बजाय, और ओपी जैसे अद्वितीय पहचानकर्ता का उपयोग करने के बजाय, क्या आप "टाइप-पहचानकर्ता" का उपयोग कर सकते हैं? उदाहरण के लिए, यदि मेरी तालिका में 3 प्रकार की कोशिकाएं थीं- एक बहुत जटिल उप-लेआउट वाला, एक Style1 के साथ, और Style2 के साथ, मुझे उन तीनों को अलग से पहचानना चाहिए और फिर डेक्यू nil पर आने पर उन्हें पुनर्निर्माण करना चाहिए।

उदाहरण के लिए:

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{ 
    NSString* ident = @""; 
    if(indexPath.section == 0) ident= @"complicated"; 
    if(indexPath.section == 1) ident= @"style1"; 
    if(indexPath.section == 2) ident = @"style2"; 

    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:ident]; 

    if(cell == nil){ 

     if(ident == @"complicated"){ 
      cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:ident] autorelease]; 
     // do excessive subview building 
     } 
     if(ident == @"style1"){ 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle1 reuseIdentifier:ident] autorelease]; 
     } 

     if(ident == @"style2"){ 
      cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle2 reuseIdentifier:ident] autorelease]; 
     } 


    } 
    if(ident == @"complicated"){ 
     // change the text/etc (unique values) of our many subviews 
    } 
    if(ident == @"style1"){ 
     [[cell textLabel] setText:@"Whatever"]; 
    } 
    if(ident == @"style2"){ 
     [[cell textLabel] setText:@"Whateverelse"]; 
    } 

    return cell; 
} 

(क्योंकि मैं इसे यहाँ लिखा था इस कोड को शायद नहीं चलेगा, लेकिन उम्मीद है कि आप प्राप्त विचार।)

मुझे नहीं लगता कि एप्पल बनाया होगा पहचानकर्ताओं के साथ पूरे पुन: प्रयोज्य सेल विचार अगर वे सभी पहचानकर्ता "cell" होना चाहते थे, तो आपको नहीं लगता?

+0

आपके मामले में मैं प्रत्येक सेल लेआउट के लिए एक पहचानकर्ता का उपयोग करता हूं। जिसका अर्थ है आपके "जटिल" कोशिकाओं में से एक, "शैली 1" कोशिकाओं के लिए और शायद शैली 2 कोशिकाओं के लिए एक तिहाई, यदि उनके सबव्यू शैली 1 से अलग हैं। मामले में डेक्यू रिटर्न शून्य में, टैग के साथ सेल का सबव्यू जोड़ें (एक enum या कुछ में परिभाषित), और फिर उन्हें प्रारंभ करें। मामले में डेक्यू एक सेल लौटाता है, बस टैग का उपयोग करके सबव्यूव पुनर्प्राप्त करें और उन्हें बदलें। प्रत्येक अनुभाग के लिए एक विधि में अपना कोड अलग करना भी अच्छा होगा :) – Jukurrpa

+0

यह एक अच्छा जवाब है। मैंने इसे वोट दिया। –

13

प्रलेखन जिसने मुझे समझने में मदद की कि बेवकूफ तरीका (जिसे आपने पहले वर्णित किया है) अनुभाग initWithStyle:reuseIdentifier: विधि पर सबसे अच्छा काम करता है।

reuseIdentifier उपधारा पढ़ता है:

आप एक ही फार्म की सभी कोशिकाओं के लिए एक ही पुन: उपयोग के पहचानकर्ता का उपयोग करना चाहिए।

और "चर्चा" उपधारा पढ़ता है:

पुन: उपयोग पहचानकर्ता एक तालिका दृश्य की उन कोशिकाओं (पंक्तियाँ) एक ही सामान्य विन्यास है, शून्य से सेल सामग्री के साथ जुड़ा हुआ है।

ये बयान कि मुहावरेदार तरीका है अपने UITableViewDataSource प्रत्येक दिखाई पंक्ति में एक सेल वस्तु उपलब्ध पंक्तियों की कुल संख्या की परवाह किए बिना बनाता है के लिए dequeueReusableCellWithIdentifiertableView:cellForRowAtIndexPath: अपने क्रियान्वयन के अंदर उपयोग करने के लिए यह मेरे लिए स्पष्ट कर दूं।

1

UITableView आंतरिक रूप से "टेम्पलेट" के रूप में पहचानकर्ता के साथ एक सेल का उपयोग करता है। तो अगली बार जब आप (टेबल के रूप में पढ़ते हैं) डेक करने का प्रयास करते हैं, तो यह सिर्फ एक नया सेल बनाता है लेकिन संग्रहित ऑब्जेक्ट का उपयोग टेम्पलेट के रूप में करता है। इसलिए आपको संदर्भ के अनुसार सेल सामग्री को प्रतिबिंबित करने के लिए अभी भी अपना यूआई अपडेट करना होगा।

इसका यह भी अर्थ है कि UITableView हमारे लिए कोशिकाओं के स्मृति प्रबंधन कर रहा है, प्रति से। सिद्धांत रूप में, दृश्यमान कोशिकाओं के रूप में बहुत से UITableViewCell ऑब्जेक्ट्स होंगे। लेकिन व्यावहारिक रूप से, स्मृति जारी होने की प्रतीक्षा में कुछ और इंतजार हो सकते हैं।

यह मूल रूप से मेमोरी को बड़ा समय बचाता है, परिदृश्यों में esp जहां आपके पास 1000 सेल्स हैं।

किसी भी पोर्टेबल डिवाइस पर जहां स्मृति प्रीमियम पर है, हमें किसी भी स्मृति के आवंटन को अंतिम संभव पल में स्थगित करना चाहिए और इसे अपना काम पूरा करने के पल को छोड़ देना चाहिए। dequeAndReusing एक सेल इसे प्राप्त करता है और यह बहुत अच्छी तरह से करता है।

दूसरी तरफ, यदि आपका सेल एक अनुकूलित सेल है, तो हम संभवतः एक निब लोड कर सकते हैं और इससे निकालेंगे। यदि यह मामला है, तो आप या तो डेक करने के लिए पहचानकर्ता का उपयोग कर सकते हैं या आप इसे निब से लोड कर सकते हैं। प्रक्रिया में कोई अंतर नहीं है।

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

+0

कस्टम कक्ष भी तालिका दृश्य स्मृति कतार प्रणाली द्वारा प्रबंधित किए जाते हैं, जब तक उनके पास 'पहचानकर्ता' सेट होता है। – Tim

0

अन्य कोशिकाओं से सेल को अलग करने के लिए आप सेल की टैग प्रॉपर्टी का उपयोग कर सकते हैं या यदि आप कस्टम सेल का उपयोग कर रहे हैं तो UITableViewCell उपclassing करते समय कस्टम सेल में किसी भी नई संपत्ति को शुरू करने के माध्यम से यह बहुत आसान है।

हालांकि इन सब आप अटक कर रहे हैं और अभी भी सेल प्राप्त करने की आवश्यकता के बाद, तो आप कोड

UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]

जबकि यह हद तक बचा जाना चाहिए, क्योंकि यह सेल के प्रति पैदा करता है, लेकिन निम्न कार्य कोशिश कर सकते हैं मौजूदा सेल को वापस न करें, जबकि सामग्री समान मानों का होगा।

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