एक Nib से पुन: प्रयोज्य UITableViewCell लोड हो रहा है


89

मैं कस्टम UITableViewCells डिज़ाइन करने और http://forums.macrumors.com/showthread.php?t=545061 पर पाए गए धागे में वर्णित तकनीक का उपयोग करके उन्हें ठीक से लोड करने में सक्षम हूं । हालाँकि, उस पद्धति का उपयोग करने से अब आप सेल को पुन: उपयोग करने की अनुमति नहीं देते हैं, जिसका अर्थ है कि आपको प्रत्येक कॉल पर प्रत्येक सेल के पूरे नए उदाहरण बनाने होंगे। क्या किसी ने फिर भी किसी विशेष सेल प्रकार को पुन: उपयोग के लिए कैश करने का एक अच्छा तरीका निकाला है, लेकिन फिर भी उन्हें इंटरफ़ेस बिल्डर में डिज़ाइन करने में सक्षम है?

जवाबों:


74

उचित विधि हस्ताक्षर के साथ एक विधि लागू करें:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

इस पद्धति को कहां लागू किया जाए?
कृष्णन

2
आपके UITableViewCell उपवर्ग में। डेवलपर
.apple.com

5
यह जोखिम भरा है। यदि आपके सेल उपवर्ग के दो उपवर्ग हैं, और एक ही तालिका दृश्य में इन दोनों का उपयोग करें तो क्या होगा? यदि वे सुपर पर पुनः उपयोग पहचानकर्ता कॉल भेजते हैं, तो आप गलत प्रकार के एक सेल को समाप्त कर देंगे .............. मुझे लगता है कि आपको reuseIdentifier विधि को ओवरराइड करने की आवश्यकता है, लेकिन क्या यह एक पहचाने गए पहचानकर्ता को लौटाता है स्ट्रिंग।
SK9

3
यह सुनिश्चित करने के लिए कि यह अद्वितीय है, आप कर सकते हैं:return NSStringFromClass([self class]);
ivanzoid

119

दरअसल, चूंकि आप इंटरफ़ेस बिल्डर में सेल का निर्माण कर रहे हैं, बस पुन: उपयोग पहचानकर्ता को वहां सेट करें:

IB_reuse_identifier

या यदि आप Xcode 4 चला रहे हैं, तो गुण निरीक्षक टैब देखें:

यहां छवि विवरण दर्ज करें

(संपादित करें: आपके XIB द्वारा XCode के उत्पन्न होने के बाद, इसमें एक खाली UIView शामिल है, लेकिन हमें UITViewViewCell की आवश्यकता है, इसलिए आपको मैन्युअल रूप से UIView को निकालना होगा और एक टेबल व्यू सेल सम्मिलित करना होगा। बेशक, IB किसी भी UITableViewCell पैरामीटर को नहीं दिखाएगा। UIView।)


यदि मैं इस Nib द्वारा निर्मित सेल का उपयोग एक से अधिक कोशिकाओं के लिए करता हूं, तो मैं क्या पहचानकर्ता सेट करूं? तीस हमें एक ही पहचानकर्ता के साथ दो कोशिकाओं को ले जाएगा।
कृष्णन

4
इसे एक विशिष्ट पहचानकर्ता के रूप में न समझें - इसे एक प्रकार के नाम की तरह समझें।
टिम कीटिंग

मैं Xcode 4.3.3 में अंतर्निहित इंटरफ़ेस बिल्डर के माध्यम से एक पहचानकर्ता सेट करने का विकल्प नहीं देख रहा हूं। मैं निश्चित रूप से अपने UITableViewCell उपवर्ग के लिए कक्षा निर्धारित कर रहा हूं। क्या मैं इसे याद कर रहा हूं, या यह छूट गया है?
टायलर

3
ठीक है, मैंने अपनी समस्या हल कर ली। यदि आप इंटरफ़ेस बिल्डर (Xcode 4 के भीतर) में एक UIView ऑब्जेक्ट से शुरू करते हैं, और इसके वर्ग को UITableViewCell में बदलते हैं, तो आपको सेल-विशिष्ट गुण पुन: उपयोग करने वाले पहचानकर्ता की तरह नहीं मिलते हैं। इसे प्राप्त करने के लिए, आपको एक खाली xib के साथ शुरू करना है और एक टेबल सेल ऑब्जेक्ट में खींचें, जिसमें तब सेल-विशिष्ट गुण होंगे जिन्हें आप संपादित कर सकते हैं।
टायलर

1
@ कृष्णन इस तरह से सोचें - जब आप पहचानकर्ता X के साथ टेबल व्यू सेल बनाते हैं, तो आप कह रहे हैं "मुझे X लेबल वाले पूल से सेल दें।" यदि पूल मौजूद है, और वहां एक मुफ्त सेल है, तो यह आपको देता है। अन्यथा, यह पूल (यदि आवश्यक हो) बनाता है, तो सेल को समाचार दें, इसे "एक्स" लेबल करता है, और फिर इसे आपको सौंप देता है। तो कोशिकाएँ अद्वितीय हो सकती हैं - जैसे आप एक विशेष पहचानकर्ता के साथ केवल एक सेल के साथ एक पूल बना सकते हैं - लेकिन लाइब्रेरी स्मृति आवंटन / डीललोच से बचने के लिए एक मुफ्त सूची जैसी रणनीति का उपयोग करती है।
टिम कीटिंग

66

अब, iOS 5 में उसके लिए उपयुक्त यूआईटेबल व्यू विधि है:

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

10
इस उत्तर में अन्य उत्तर, स्वीकृत उत्तर सहित, पुरानी सलाह शामिल हैं।
कालिन कोलक्लेयर

क्या यह पिछड़ा संगत है? मेरा मतलब है कि अगर मैं एसडीके 5.0 के साथ एक ऐप विकसित करता हूं और न्यूनतम 4.0 को लक्षित करता हूं तो क्या ऐप उदाहरण के लिए आईओएस 4.0 के साथ उपकरणों पर चलेगा?
अबोल्फूडौड

1
नहीं, यह पीछे की ओर संगत नहीं है, क्योंकि iOS 5.0 में कोई नया एपीआई नहीं है।
मार्जापावर ५'१३

इसे अपने नियंत्रक में एकीकृत करने के तरीके का उदाहरण दिया गया है: mindfiresolutions.com/…
mblackwell8

47

मुझे याद नहीं है कि मुझे यह कोड मूल रूप से कहां मिला, लेकिन यह मेरे लिए अब तक बहुत अच्छा काम कर रहा है।

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

उदाहरण इंटरफ़ेस बिल्डर सेटअप ...

वैकल्पिक शब्द


12

इस प्रश्न का उत्तर मैंने दिया:

क्या इंटरफ़ेस बिल्डर में NSCell उपवर्गों को डिजाइन करना संभव है?

IB में UITableViewCell डिजाइन करना न केवल संभव है, बल्कि यह वांछनीय है क्योंकि अन्यथा सभी तत्वों के मैनुअल वायरिंग और प्लेसमेंट बहुत थकाऊ हैं। जब तक आप संभव हो सभी तत्वों को अपारदर्शी बनाने के लिए सावधान रहें तब तक Performaance ठीक है। पुन: उपयोग UITableViewCell के गुणों के लिए IB में सेट किया गया है, तो आप कोड का मिलान तब उपयोग करते हैं जब कोड में dequeue करने का प्रयास किया जाता है।

मैंने पिछले साल WWDC के कुछ प्रस्तुतकर्ताओं से भी सुना था कि आपको IB में टेबल व्यू सेल नहीं बनाने चाहिए, लेकिन यह चारपाई का भार है।


2
यदि आपको पारदर्शिता की आवश्यकता है और अच्छा स्क्रॉल प्रदर्शन चाहते हैं तो आपको आईबी में टेबल व्यू सेल नहीं बनाना चाहिए। कुछ UI के लिए, आपको पारदर्शिता की आवश्यकता होती है (जैसे ग्राफिक्स पर पाठ रेंडर करने के लिए)। कभी-कभी पुराने (प्री-ए 4) हार्डवेयर पर अच्छी स्क्रॉलिंग प्राप्त करने का एकमात्र तरीका कोड में रेंडर करना है, जिससे कि कई पारदर्शी परतों के जीपीयू से बचा जा सके।
निक फोर्ज

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

7

IOS लगभग 4.0 के रूप में, iOS डॉक्स में विशिष्ट निर्देश हैं जो इस काम को सुपर-फास्ट बनाते हैं:

http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7

UITableViewCell को उप-वर्ग करने की बात करने के लिए नीचे स्क्रॉल करें।


6

यहाँ एक और विकल्प है:

NSString * cellId = @"reuseCell";  
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];

for (id obj in nibObjects)
{
    if ([obj isKindOfClass:[CustomTableCell class]])
    {
        cell = obj;
        [cell setValue:cellId forKey:@"reuseIdentifier"];
        break;
    }
}

ध्यान दें कि यह अब तक का एकमात्र समाधान है, जिसके UITableViewCellलिए एक विशिष्ट मान सेट करने के लिए आपके कस्टम को उप-वर्ग करने की आवश्यकता नहीं है reuseIdentifer। मुझे लगता है कि यह वही है जो मूल ऑप वास्तव में खोज रहा था।
चारशीप

मुझे आशा है कि Apple इस का उपयोग करने के लिए मेरे आवेदन से इनकार नहीं करेगा ... मैं "स्थिर" कोशिकाओं को प्राप्त करने के लिए इसका उपयोग कर रहा हूं क्योंकि मेरे तालिका दृश्य में, एक सेल भरने की प्रक्रिया शांत धीमी है। इस तरह मुझे बस इसे एक बार निष्पादित करना होगा (प्रत्येक पंक्ति को एक अलग पहचानकर्ता देना)। धन्यवाद!
रिकर्ड पेरेज़ डेल कैम्पो

बहुत उपयोगी है क्योंकि मैन्युअल रूप से इसे स्थापित करने के लिए कोई UITableViewCell विधि नहीं है!
जेसी

2

मैं अपने कस्टम व्यू सेल को एक समान तरीके से बनाता हूं - सिवाय इसके कि मैं सेल को एक IBOutlet के माध्यम से जोड़ता हूं।

[nib objectAt...]दृष्टिकोण सरणी में आइटम के पदों में परिवर्तन की संभावना है।

UIViewControllerदृष्टिकोण अच्छा है - बस इसे करने की कोशिश, और यह अच्छा पर्याप्त काम करता है।

परंतु...

सभी मामलों में initWithStyleकंस्ट्रक्टर को नहीं बुलाया जाता है, इसलिए कोई डिफ़ॉल्ट आरंभीकरण नहीं किया जाता है।

मैंने विभिन्न स्थानों का उपयोग करने के बारे में पढ़ा है initWithCoderया नहीं awakeFromNib, लेकिन कोई भी निर्णायक सबूत नहीं है कि इनमें से कोई भी सही तरीका है।

स्पष्ट रूप से कुछ आरंभीकरण विधि को कॉल करने के अलावा विधि में cellForRowAtIndexPathमुझे अभी तक इसका जवाब नहीं मिला है।


awakeFromNib किसी NIB से लोड की जा रही वस्तु पर प्रतिक्रिया करने का सही तरीका है।
जॉन हेस

2

कुछ समय पहले मैंने इस विषय पर एक शानदार ब्लॉग पोस्ट blog.atebits.com पर पाया , और तब से मैंने अपने सभी UITableViewCells को करने के लिए लॉरेन ब्रिचर ABTableViewCell क्लास का उपयोग शुरू कर दिया है।

आप अपने सभी विजेट्स को डालने के लिए एक साधारण कंटेनर UIView के साथ समाप्त होते हैं, और स्क्रॉलिंग बहुत तेज़ होती है।

आशा है कि यह उपयोगी है।


2

यह तकनीक भी काम करती है और स्मृति प्रबंधन के लिए आपके विचार नियंत्रक में एक कायरतापूर्ण आइवर की आवश्यकता नहीं होती है। यहां, कस्टम टेबल व्यू सेल एक एक्सिब में रहता है जिसका नाम "CustomCell.xib" है।

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }

1
संग्रह और अराजकता पूर्णतः अनावश्यक है।
ब्रायन हेनरी

1
यदि आप इसे समाप्त नहीं किया जा सकता है, तो सेल को उसके निब से लोड करने के साथ ठीक होने पर अभिलेखीकरण / अनअर्काइविंग अनावश्यक है। हालाँकि, यदि आप सेल को उसके निब से ठीक एक बार लोड करना चाहते हैं , तो आपको इसे मेमोरी में कैश करना होगा। मुझे लगता है कि NSKeyedArchiving का उपयोग करके कैशिंग पूरा होता है क्योंकि UITableViewCell NSCopying को लागू नहीं करता है।
बिल गैरीसन

1
कहा जाता है कि सेल को लोड करने के लिए यूआईएनबी का उपयोग करने से एक ही प्रभाव प्राप्त होता है: एक बार डिस्क से लोड, उसके बाद मेमोरी से लोड।
बिल गैरिसन

2

लुई विधि ने मेरे लिए काम किया। यह वह कोड है जिसका उपयोग मैं नीब से UITableViewCell बनाने के लिए करता हूं:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *simpleTableIdentifier = @"CustomCell";

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}         

return cell;
}

1

Gustavogb समाधान मेरे लिए काम नहीं करता है, जो मैंने कोशिश की है:

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

यह काम करने लगता है। BlogTableViewCell सेल के लिए IBOutlet है और ChainesController फ़ाइल का मालिक है।


1

UITableView डॉक्स से संबंधित dequeueWithReuseIdentifier: "सेल ऑब्जेक्ट को पुन: उपयोग करने के लिए पहचानने वाला एक स्ट्रिंग। डिफ़ॉल्ट रूप से, एक पुन: प्रयोज्य सेल का पहचानकर्ता इसका वर्ग नाम है, लेकिन आप इसे किसी भी मनमाने मूल्य पर बदल सकते हैं।"

ओवरराइडिंग -reuseIdentifer अपने आप में जोखिम भरा है। यदि आपके सेल उपवर्ग के दो उपवर्ग हैं, और एक ही तालिका दृश्य में इन दोनों का उपयोग करने से क्या होता है? यदि वे सुपर पर पुनः उपयोग पहचानकर्ता कॉल भेजते हैं, तो आप गलत प्रकार के सेल को हटा देंगे .............. मुझे लगता है कि आपको reuseIdentifier विधि को ओवरराइड करने की आवश्यकता है, लेकिन क्या यह एक पहचाने गए पहचानकर्ता को लौटाता है स्ट्रिंग। या, यदि कोई निर्दिष्ट नहीं किया गया है, तो क्या यह कक्षा को एक स्ट्रिंग के रूप में लौटाता है।


0

इसके लायक क्या है, मैंने एक iPhone इंजीनियर से iPhone Tech Talks में से एक के बारे में पूछा। उनका जवाब था, "हां, कोशिकाओं को बनाने के लिए आईबी का उपयोग करना संभव है। लेकिन नहीं। कृपया, नहीं।"


1
अजीब है कि। NY टॉक में कम से कम दो वार्ताओं में डेमो कोड था जो आईबी में निर्मित कोशिकाओं का उपयोग करता था।
शॉन क्रेवर

3
मुझे यकीन नहीं है कि मैं इस पर विश्वास करता हूं क्योंकि वे Apple के एडवांस्ड टेबल व्यू सेल्स उदाहरण प्रोजेक्ट में कोशिकाओं को बनाने के लिए IB का उपयोग करते हैं।
iwasrobbed

उसके लिए धन्यवाद। हर बार जब मैंने ऐसा किया है तो मैं समस्याओं में चला गया हूं। यह क्यों हो सकता है
स्कॉरुलिस

उसे शायद इसके बारे में पर्याप्त ज्ञान नहीं था।
२१:२५ बजे आर्यक्स्ट

0

मैंने बेन मोशर (धन्यवाद!) के रूप में Apple के निर्देशों का पालन किया लेकिन पाया कि Apple एक महत्वपूर्ण बिंदु है। आईबी में वे जिस वस्तु को डिजाइन करते हैं, वह सिर्फ एक यूआईटेबल व्यूसेल है, जैसा कि वह चर है जो वे इससे लोड करते हैं। लेकिन अगर आप वास्तव में इसे UITableViewCell के कस्टम उपवर्ग के रूप में स्थापित करते हैं, और उपवर्ग के लिए कोड फाइलें लिखते हैं, तो आप कोड में IBOutlet घोषणाएं और IBAction तरीके लिख सकते हैं और उन्हें आईबी में आपके कस्टम तत्वों को तार कर सकते हैं। फिर इन तत्वों को एक्सेस करने के लिए व्यू टैग्स का उपयोग करने की आवश्यकता नहीं है और आप किसी भी तरह का क्रेजी सेल बना सकते हैं। यह कोको टच स्वर्ग है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.