आप Xib फ़ाइलों से कस्टम UITableViewCells कैसे लोड करते हैं?


293

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

यहाँ कुछ कोड का उपयोग मैंने किया है:

static NSString *CellIdentifier = @"MyCellIdentifier";

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

इस कोड का उपयोग करने के लिए, MyCell.m / .h, का एक नया उपवर्ग बनाएं UITableViewCellऔर अपने IBOutletsइच्छित घटकों के लिए जोड़ें । फिर एक नई "खाली XIB" फ़ाइल बनाएं। IB में Xib फ़ाइल खोलें, एक UITableViewCellऑब्जेक्ट जोड़ें , इसके पहचानकर्ता को "MyCellIdentifier" पर सेट करें, और इसकी कक्षा को MyCell पर सेट करें और अपने घटकों को जोड़ें। अंत में, IBOutletsघटकों से कनेक्ट करें । ध्यान दें कि हमने फ़ाइल का स्वामी आईबी में सेट नहीं किया है।

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

तो Xibs से कोशिकाओं को लोड करने के लिए विहित तरीका क्या है? क्या हम फ़ाइल का स्वामी सेट करते हैं? क्या हमें किसी कारखाने की आवश्यकता है? यदि हां, तो कारखाने के लिए कोड कैसा दिखता है? यदि कई समाधान हैं, तो आइए उनमें से प्रत्येक के पेशेवरों और विपक्षों को स्पष्ट करें ...


2
क्या वास्तव में प्रश्न पूछने के लिए कोई व्यक्ति इस विषय को संपादित कर सकता है, "आप Xib फ़ाइलों से कस्टम UITableViewCells कैसे लोड करते हैं?" (ध्यान दें कि अगर यह स्टैकओवरफ्लो पर संभव नहीं है।)
स्टीवन फिशर

1
IOS 5 और उससे आगे के लिए, यह समाधान है: stackoverflow.com/questions/15591364/… , जो कि giuseppe के समाधान के समान है।
मैट बेकर

त्वरित टिप्पणी, सरल (2013 परिवेश) जवाब यहाँ stackoverflow.com/questions/15378788/... jamihash
fattie

जवाबों:


288

यहां दो विधियां हैं जो मूल लेखक राज्यों को एक आईबी इंजीनियर द्वारा अनुशंसित किया गया था

अधिक जानकारी के लिए वास्तविक पोस्ट देखें। मुझे विधि # 2 पसंद है क्योंकि यह सरल लगता है।

विधि # 1:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Create a temporary UIViewController to instantiate the custom cell.
        UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:@"BDCustomCell" bundle:nil];
        // Grab a pointer to the custom cell.
        cell = (BDCustomCell *)temporaryController.view;
        [[cell retain] autorelease];
        // Release the temporary UIViewController.
        [temporaryController release];
    }

    return cell;
}

विधि # 2:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BDCustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];
    }

    return cell;
}

अद्यतन (2014): विधि # 2 अभी भी मान्य है लेकिन अब इसके लिए कोई दस्तावेज नहीं है। यह आधिकारिक डॉक्स में हुआ करता था लेकिन अब स्टोरीबोर्ड के पक्ष में हटा दिया गया है।

मैंने Github पर एक कार्यशील उदाहरण पोस्ट किया:
https://github.com/bentford/NibTableCellExample

स्विफ्ट 4.2 के लिए संपादित करें

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    self.tblContacts.register(UINib(nibName: CellNames.ContactsCell, bundle: nil), forCellReuseIdentifier: MyIdentifier)
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier, for: indexPath) as! ContactsCell

    return cell
}

1
विधि 1 के लिए, क्या आपको "सेल = (BDCustomCell *) [[[अस्थायीप्रकारपत्रकारक अनुलक्षण] ऑटोरेलेज़];" इसलिए अस्थायी नियंत्रक जारी होने पर सेल जारी नहीं होती है?
टॉड कनिंघम

हम्म। # 2 के बारे में बात करने वाले दस्तावेज़ अभी भी आपको XIB फ़ाइल में सेल के मालिक को एक ज्ञात नियंत्रक वर्ग में सेट करने के लिए कहते हैं। शायद यह मायने नहीं रखता जब आप लोडिंग के दौरान मालिक को सेट करते हैं।
ऑस्कर

@OscarGoldman XIB फ़ाइल में सेल का स्वामी एक वर्ग होता है (यानी स्वामी का प्रकार।) सेल का मालिक loadNibNamed: स्वामी: विकल्प: XIB में निर्दिष्ट प्रकार का ऑब्जेक्ट है।
बेंटफोर्ड

2
@CoolDocMan विकल्प # 2 अभी भी काम करता है। समस्या निब के साथ सबसे अधिक संभावना है। यहाँ एक उदाहरण है: github.com/bentford/NibTableCellExample
bentford

2
इस पुराने पुराने कोड को इतना ऊंचा स्थान क्यों दिया गया है। Stackoverflow कुछ करते हैं: /
Nico S.

304

सही समाधान यह है:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UINib *nib = [UINib nibWithNibName:@"ItemCell" bundle:nil];
    [[self tableView] registerNib:nib forCellReuseIdentifier:@"ItemCell"];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Create an instance of ItemCell
    PointsItemCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ItemCell"];

    return cell;
}

क्या यह iOS5 ऐप्स को तोड़ने वाला है? मैंने वास्तव में UINib
एडम वेट

@AdamWaite NIB फ़ाइलों को पंजीकृत करना iOS 5 और बाद में काम करता है, इसलिए यह iOS 5 ऐप्स को नहीं तोड़ रहा है। और यूआईएनबी आईओएस 4 के बाद से भी मौजूद है
मेकी

एक अच्छे उदाहरण के लिए, शीर्ष उत्तर में संदर्भित git रेपो की जाँच करें: stackoverflow.com/questions/18746929/…
netigger

39

रजिस्टर करें

IOS 7 के बाद, इस प्रक्रिया को सरल बना दिया गया है ( तेजी से 3.0 ):

// For registering nib files
tableView.register(UINib(nibName: "MyCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")

// For registering classes
tableView.register(MyCellClass.self, forCellReuseIdentifier: "cell")

( नोट ) यह भी प्रोटोटाइप कोशिकाओं के रूप में .xibया .stroyboardफ़ाइलों में कोशिकाओं को बनाकर प्राप्त करने योग्य है । यदि आपको उनके लिए एक क्लास संलग्न करने की आवश्यकता है, तो आप सेल प्रोटोटाइप का चयन कर सकते हैं और संबंधित वर्ग ( UITableViewCellनिश्चित रूप से , का एक वंशज होना चाहिए) को जोड़ सकते हैं ।

विपंक्ति

और बाद में, ( स्विफ्ट 3.0 ) का उपयोग कर समाप्त किया गया :

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    cell.textLabel?.text = "Hello"

    return cell
}

अंतर यह है कि यह नया तरीका न केवल सेल को ख़राब करता है, बल्कि यह भी बनाता है कि गैर-मौजूद (इसका मतलब है कि आपको शेंनिगन्स करने की ज़रूरत नहीं है if (cell == nil)), और सेल उपरोक्त उदाहरण में ही उपयोग करने के लिए तैयार है।

( चेतावनी ) tableView.dequeueReusableCell(withIdentifier:for:)का नया व्यवहार है, यदि आप दूसरे को बुलाते हैं (बिना indexPath:) आपको पुराना व्यवहार मिलता है, जिसमें आपको इसकी जांच करने nilऔर इसे स्वयं करने की आवश्यकता होती है , तो UITableViewCell?रिटर्न मान देखें।

if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCellClass
{
    // Cell be casted properly
    cell.myCustomProperty = true
}
else
{
    // Wrong type? Wrong identifier?
}

और निश्चित रूप से, सेल के संबंधित वर्ग का प्रकार वह है जिसे आपने UITableViewCellउप-वर्ग के लिए .xib फ़ाइल में परिभाषित किया है , या वैकल्पिक रूप से, अन्य रजिस्टर विधि का उपयोग करके।

विन्यास

आदर्श रूप से, आपकी कोशिकाएँ पहले ही पंजीकृत और सामग्री स्थिति (जैसे लेबल और छवि दृश्य) के संदर्भ में कॉन्फ़िगर की जा चुकी हैं, जब तक आप उन्हें पंजीकृत नहीं करते हैं, और जिस cellForRowAtIndexPathविधि पर आप बस उन्हें भरते हैं।

सभी एक साथ

class MyCell : UITableViewCell
{
    // Can be either created manually, or loaded from a nib with prototypes
    @IBOutlet weak var labelSomething : UILabel? = nil
}

class MasterViewController: UITableViewController 
{
    var data = ["Hello", "World", "Kinda", "Cliche", "Though"]

    // Register
    override func viewDidLoad()
    {
        super.viewDidLoad()

        tableView.register(MyCell.self, forCellReuseIdentifier: "mycell")
        // or the nib alternative
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return data.count
    }

    // Dequeue
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "mycell", for: indexPath) as! MyCell

        cell.labelSomething?.text = data[indexPath.row]

        return cell
    }
}

और हां, यह ओब्जेक्ट में एक ही नाम से उपलब्ध है।


यहाँ objC संस्करण है:[self.tableView registerNib:[UINib nibWithNibName:@"BlaBlaTableViewCell" bundle:nil] forCellReuseIdentifier:kCellIdentifier];
Zeb

33

शॉन क्रेवर का जवाब लिया और इसे थोड़ा साफ किया।

BBCell.h:

#import <UIKit/UIKit.h>

@interface BBCell : UITableViewCell {
}

+ (BBCell *)cellFromNibNamed:(NSString *)nibName;

@end

BBCell.m:

#import "BBCell.h"

@implementation BBCell

+ (BBCell *)cellFromNibNamed:(NSString *)nibName {
    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    BBCell *customCell = nil;
    NSObject* nibItem = nil;
    while ((nibItem = [nibEnumerator nextObject]) != nil) {
        if ([nibItem isKindOfClass:[BBCell class]]) {
            customCell = (BBCell *)nibItem;
            break; // we have a winner
        }
    }
    return customCell;
}

@end

मैं अपने सभी UITableViewCell BBCell के उपवर्ग बनाता हूं, और फिर मानक को प्रतिस्थापित करता हूं

cell = [[[BBDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BBDetailCell"] autorelease];

साथ में:

cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];

16

मैंने बेंटफोर्ड की विधि # 2 का उपयोग किया :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BDCustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];
    }

    return cell;
}

यह काम करता है, लेकिन अपने कस्टम UITableViewCell .xib फ़ाइल में फ़ाइल के स्वामी के कनेक्शन के लिए देखें ।

owner:selfअपने loadNibNamedबयान में पारित करके , आप के UITableViewControllerरूप में फ़ाइल के मालिक सेट करें UITableViewCell

यदि आप क्रियाओं और आउटलेट्स को सेट करने के लिए IB में हेडर फाइल को ड्रैग और ड्रॉप करते हैं, तो यह उन्हें डिफ़ॉल्ट रूप से फाइल के ओनर के रूप में सेट करेगा।

इसके बाद से loadNibNamed:owner:options, Apple का कोड आपके गुणों को सेट करने का प्रयास करेगा UITableViewController, क्योंकि वह स्वामी है। लेकिन आपके पास उन गुणों को परिभाषित नहीं किया गया है, इसलिए आपको कुंजी मूल्य कोडिंग-अनुरूप होने के बारे में एक त्रुटि मिलती है :

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason:     '[<MyUITableViewController 0x6a383b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key myLabel.'

यदि कोई इवेंट इसके बजाय ट्रिगर हो जाता है, तो आपको एक NSInvalidArgumentException मिल जाएगी:

-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0'
*** First throw call stack:
(0x1903052 0x15eed0a 0x1904ced 0x1869f00 0x1869ce2 0x1904ec9 0x5885c2 0x58855a 0x62db76 0x62e03f 0x77fa6c 0x24e86d 0x18d7966 0x18d7407 0x183a7c0 0x1839db4 0x1839ccb 0x1f8b879 0x1f8b93e 0x585a9b 0xb904d 0x2c75)
terminate called throwing an exceptionCurrent language:  auto; currently objective-c

UITableViewCellफ़ाइल के स्वामी के बजाय अपने इंटरफ़ेस बिल्डर कनेक्शन को इंगित करने के लिए एक आसान समाधान है :

  1. कनेक्शन की सूची खींचने के लिए फ़ाइल के स्वामी पर राइट क्लिक करें
  2. कमांड-शिफ्ट -4 के साथ स्क्रीन कैप्चर करें (कैप्चर किए जाने वाले क्षेत्र का चयन करने के लिए खींचें)
  3. फ़ाइल के स्वामी से कनेक्शनों का पता लगाएं
  4. ऑब्जेक्ट पदानुक्रम में UITableCell पर राइट क्लिक करें और कनेक्शन फिर से जोड़ें।

मुझे आपके द्वारा बताई गई समस्या थी, लेकिन फाइल के मालिक के बजाय UITableViewCell से कनेक्शन कैसे इंगित करें? मुझे आपके कदम समझ में नहीं आ रहे हैं, जैसे कि स्क्रीनशॉट की आवश्यकता क्यों है? और जब मैंने आउटलेट के बगल में ऐड बटन पर क्लिक किया, तो कुछ भी नहीं होता है
x huanze

@xuhuanze मैंने एक स्क्रीनशॉट लेने का सुझाव दिया है ताकि आपके पास रिकॉर्ड हो कि फाइल का मालिक पहले से किन चीजों से जुड़ा था। फिर आप उन्हीं कनेक्शनों को फिर से बना सकते हैं। आपको कनेक्शन जोड़ने के लिए ड्रैग और ड्रॉप करना होगा - केवल एक क्लिक पर नहीं।
funroll

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

14

मैंने पोस्ट करने का फैसला किया है क्योंकि मुझे इनमें से कोई भी जवाब पसंद नहीं है - चीजें हमेशा अधिक सरल हो सकती हैं और यह अब तक का सबसे संक्षिप्त तरीका है जो मैंने पाया है।

1. इंटरफ़ेस बिल्डर में अपने Xib का निर्माण जैसा आप चाहते हैं

  • NSObject वर्ग के लिए फ़ाइल का स्वामी सेट करें
  • एक UITableViewCell जोड़ें और अपनी कक्षा को MyTableViewCellSubclass पर सेट करें - यदि आपका IB क्रैश हो जाता है (Xcode> 4 इस लेखन के रूप में), तो Xcode 4 में इंटरफ़ेस का उपयोग करने के लिए एक UIView का उपयोग करें यदि यह अभी भी चारों ओर बिछा रहा है
  • इस सेल के अंदर अपने साक्षात्कारों को लेआउट करें और अपने IBOutlet कनेक्शन को अपने। In या .h या .m (.m मेरी पसंद) के लिए संलग्न करें।

2. आपके UIViewController या UITableViewController उपवर्ग में

@implementation ViewController

static NSString *cellIdentifier = @"MyCellIdentier";

- (void) viewDidLoad {

    ...
    [self.tableView registerNib:[UINib nibWithNibName:@"MyTableViewCellSubclass" bundle:nil] forCellReuseIdentifier:cellIdentifier];
}

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCellSubclass *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    ...

    return cell;
}

3. आपके MyTableViewCellSubclass में

- (id) initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        ...
    }

    return self;
}

9

यदि आप कक्ष बनाने के लिए इंटरफ़ेस बिल्डर का उपयोग कर रहे हैं, तो जांचें कि आपने इंस्पेक्टर में पहचानकर्ता सेट किया है। तब चेक करें कि जब dequeueReusableCellWithIdentifier को कॉल किया जाए तो यह समान हो।

मैं गलती से टेबल-हैवी प्रोजेक्ट में कुछ पहचानकर्ता सेट करना भूल गया था, और प्रदर्शन परिवर्तन रात और दिन की तरह था।


8

लोड हो रहा है XIBs से UITableViewCells कोड का एक बहुत बचाता है, लेकिन आमतौर पर भयानक स्क्रॉल गति (वास्तव में, यह XIB नहीं है, लेकिन UIViews का अत्यधिक उपयोग जो इस कारण होता है)।

मेरा सुझाव है कि आप इस पर एक नज़र डालें: लिंक संदर्भ


6

यहाँ क्लास विधि है जो मैं XIBs से बाहर कस्टम सेल बनाने के लिए उपयोग कर रहा हूँ:

+ (CustomCell*) createNewCustomCellFromNib {

    NSArray* nibContents = [[NSBundle mainBundle]
                            loadNibNamed:@"CustomCell" owner:self options:NULL];

    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    CustomCell *customCell= nil;
    NSObject* nibItem = nil;

    while ( (nibItem = [nibEnumerator nextObject]) != nil) {

        if ( [nibItem isKindOfClass: [CustomCell class]]) {
            customCell = (CustomCell*) nibItem;

            if ([customCell.reuseIdentifier isEqualToString: @"CustomCell"]) {
                break; // we have a winner
            }
            else
                fuelEntryCell = nil;
        }
    }
    return customCell;
}

फिर, XIB में, मैंने कक्षा का नाम सेट किया, और पहचानकर्ता का पुन: उपयोग किया। उसके बाद, मैं उस विधि को अपने दृश्य नियंत्रक के बजाय कॉल कर सकता हूं

[[UITableViewCell] alloc] initWithFrame:]

यह काफी तेजी से पर्याप्त है, और मेरे दो शिपिंग अनुप्रयोगों में उपयोग किया जा रहा है। यह कॉल करने की तुलना में अधिक विश्वसनीय है [nib objectAtIndex:0], और मेरे दिमाग में कम से कम, स्टीफन बरलोट के उदाहरण की तुलना में अधिक विश्वसनीय है क्योंकि आपको केवल एक XIB से बाहर का दृश्य देखने की गारंटी है जो कि सही प्रकार है।


5

सही समाधान यह है

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"CustomCell"];
}

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

4

एनआईबी को रीलोड करना महंगा है। इसे एक बार लोड करने के लिए बेहतर है, फिर जब आपको सेल की आवश्यकता हो तो वस्तुओं को तुरंत हटा दें। ध्यान दें कि आप इस विधि (Apple के "registerNIB" iOS5 का उपयोग करते हुए, NIB, यहां तक ​​कि कई सेल में UIImageViews आदि जोड़ सकते हैं, केवल एक शीर्ष स्तर की वस्तु - बग 10580062 "iOS5 tableView registerNib: overly प्रतिबंधक की अनुमति देता है")

तो मेरा कोड नीचे है - आप एनआईबी में एक बार पढ़ते हैं (जैसा मैंने किया था या व्यूलोड में शुरू में - जो भी हो। तब से, आप निब को वस्तुओं में बदल देते हैं, फिर आपको जो चाहिए वह उठाते हैं। यह निब को लोड करने की तुलना में बहुत अधिक कुशल है। बार बार।

static UINib *cellNib;

+ (void)initialize
{
    if(self == [ImageManager class]) {
        cellNib = [UINib nibWithNibName:@"ImageManagerCell" bundle:nil];
        assert(cellNib);
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"TheCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if(cell == nil) {
        NSArray *topLevelItems = [cellNib instantiateWithOwner:nil options:nil];
        NSUInteger idx = [topLevelItems indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
                            {
                                UITableViewCell *cell = (UITableViewCell *)obj;
                                return [cell isKindOfClass:[UITableViewCell class]] && [cell.reuseIdentifier isEqualToString:cellID];
                            } ];
        assert(idx != NSNotFound);
        cell = [topLevelItems objectAtIndex:idx];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"Howdie %d", indexPath.row];

    return cell;
}

4

यह जांचें - http://eppz.eu/blog/custom-uitableview-cell/ - नियंत्रक कार्यान्वयन में एक पंक्ति को समाप्त करने वाले छोटे वर्ग का उपयोग करके वास्तव में सुविधाजनक तरीका:

-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self];
}

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


3

इसे करने का सही तरीका UITableViewCell उपवर्ग कार्यान्वयन, हेडर और XIB बनाना है। XIB में किसी भी दृश्य को हटा दें और सिर्फ एक टेबल सेल जोड़ें। वर्ग को UITableViewCell उपवर्ग के नाम के रूप में सेट करें। फ़ाइल स्वामी के लिए, इसे UITableViewController उपवर्ग वर्ग नाम बनाएं। TableViewCell आउटलेट का उपयोग करके फ़ाइल स्वामी को सेल से कनेक्ट करें।

हेडर फ़ाइल में:

UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;

कार्यान्वयन फ़ाइल में:

@synthesize tableViewCell = _tableViewCell;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellIdentifier = @"reusableCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:kCellIdentifier owner:self options:nil];
        cell = _tableViewCell;
        self.tableViewCell = nil;
    }

    return cell;
}

3

इसके लिए मैं क्या करता हूं यह IBOutlet UITableViewCell *cellआपके नियंत्रक वर्ग में घोषित किया गया है। फिर NSBundle loadNibNamedक्लास विधि लागू करें , जो UITableViewCellऊपर घोषित सेल को खिलाएगी।

Xib के लिए मैं एक खाली xib बनाऊंगा और UITableViewCellIB में ऑब्जेक्ट को जोड़ूंगा जहां इसे आवश्यकतानुसार सेटअप किया जा सकता है। यह दृश्य तब IBOutletनियंत्रक वर्ग में सेल से जुड़ा होता है ।

- (UITableViewCell *)tableView:(UITableView *)table
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%@ loading RTEditableCell.xib", [self description] );

    static NSString *MyIdentifier = @"editableCellIdentifier";
    cell = [table dequeueReusableCellWithIdentifier:MyIdentifier];

    if(cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"RTEditableCell"
                                      owner:self
                                    options:nil];
    }

    return cell;
}

NSBundle परिवर्धन loadNibNamed (ADC लॉगिन)

cocoawithlove.com लेख मैं इस अवधारणा से आया (फोन नंबर नमूना एप्लिकेशन प्राप्त करें)


3
  1. अपनी खुद की अनुकूलित वर्ग AbcViewCellउपवर्ग UITableViewCellबनाएं (सुनिश्चित करें कि आपकी कक्षा का फ़ाइल नाम और नीब फ़ाइल नाम समान हैं)

  2. यह एक्सटेंशन क्लास विधि बनाएं।

    extension UITableViewCell {
        class func fromNib<T : UITableViewCell>() -> T {
            return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0] as! T
        }
    }
  3. इसका इस्तेमाल करें।

    let cell: AbcViewCell = UITableViewCell.fromNib()


2

पहले अपनी कस्टम सेल फ़ाइल आयात करें #import "CustomCell.h"और फिर नीचे बताए अनुसार प्रतिनिधि विधि बदलें:

- (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;
}

2

में स्विफ्ट 4.2 और Xcode 10

मेरे पास तीन XIB सेल फाइलें हैं

ViewDidLoad में अपनी XIB फ़ाइलों को इस तरह पंजीकृत करें ...

यह पहला तरीका है

tableView.register(UINib.init(nibName: "XIBCell", bundle: nil), forCellReuseIdentifier: "cell1")
tableView.register(UINib.init(nibName: "XIBCell2", bundle: nil), forCellReuseIdentifier: "cell2")
//tableView.register(UINib.init(nibName: "XIBCell3", bundle: nil), forCellReuseIdentifier: "cell3")

दूसरा दृष्टिकोण सेलफ़ोररैट इंडेक्सपथ में सीधे XIB फ़ाइलों को पंजीकृत करें :

यह मेरा टेबलव्यू प्रतिनिधि कार्य है

//MARK: - Tableview delegates
override func numberOfSections(in tableView: UITableView) -> Int {

    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return 6
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //This is first approach
    if indexPath.row == 0 {//Load first XIB cell
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! XIBCell
        return placeCell
    //Second approach
    } else if indexPath.row == 5 {//Load XIB cell3
        var cell = tableView.dequeueReusableCell(withIdentifier:"cell3") as? XIBCell3
        if cell == nil{
            let arrNib:Array = Bundle.main.loadNibNamed("XIBCell3",owner: self, options: nil)!
            cell = arrNib.first as? XIBCell3
        }

        //ADD action to XIB cell button
        cell?.btn.tag = indexPath.row//Add tag to button
        cell?.btn.addTarget(self, action: #selector(self.bookbtn1(_:)), for: .touchUpInside);//selector

        return cell!
    //This is first approach
    } else {//Load XIB cell2
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell2") as! XIBCell2

        return placeCell
    }

}

1

यहाँ इसके लिए मेरी विधि है: XIB फ़ाइलों से कस्टम UITableViewCells लोड हो रहा है ... फिर भी एक और विधि

यह विचार UITableViewCellएक IBOutlet UIView *contentप्रॉपर्टी और प्रत्येक कस्टम सबव्यू के लिए एक प्रॉपर्टी के साथ एक सैंपेल उपवर्ग बनाने के लिए है जिसे आपको कोड से कॉन्फ़िगर करने की आवश्यकता है। फिर एक नमूनाCell.xib फ़ाइल बनाने के लिए। इस निब फ़ाइल में, फ़ाइल के मालिक को सैंपेलसेल में बदलें। UIViewअपनी आवश्यकताओं के अनुसार एक सामग्री आकार जोड़ें । अपने इच्छित सभी साक्षात्कार (लेबल, छवि दृश्य, बटन आदि) जोड़ें और कॉन्फ़िगर करें। अंत में, कंटेंट व्यू और सबव्यू को फाइल मालिक से लिंक करें।


1

यहाँ कोशिकाओं के पंजीकरण के लिए एक सार्वभौमिक दृष्टिकोण दिया गया है UITableView:

protocol Reusable {
    static var reuseID: String { get }
}

extension Reusable {
    static var reuseID: String {
        return String(describing: self)
    }
}

extension UITableViewCell: Reusable { }

extension UITableView {

func register<T: UITableViewCell>(cellClass: T.Type = T.self) {
    let bundle = Bundle(for: cellClass.self)
    if bundle.path(forResource: cellClass.reuseID, ofType: "nib") != nil {
        let nib = UINib(nibName: cellClass.reuseID, bundle: bundle)
        register(nib, forCellReuseIdentifier: cellClass.reuseID)
    } else {
        register(cellClass.self, forCellReuseIdentifier: cellClass.reuseID)
    }
}

स्पष्टीकरण:

  1. Reusableप्रोटोकॉल अपने वर्ग के नाम से सेल आईडी बनाता है। सुनिश्चित करें कि आप सम्मेलन का पालन करें cell ID == class name == nib name:।
  2. UITableViewCellReusableप्रोटोकॉल के अनुरूप है ।
  3. UITableView विस्तार सार निब या कक्षा के माध्यम से कोशिकाओं को पंजीकृत करने के अंतर को दूर करता है।

उपयोग उदाहरण:

override func viewDidLoad() {
    super.viewDidLoad()
    let tableView = UITableView()
    let cellClasses: [UITableViewCell.Type] = [PostCell.self, ProfileCell.self, CommentCell.self]
    cellClasses.forEach(tableView.register)
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: PostCell.self.reuseID) as? PostCell
    ...
    return cell
}

0

मुझे नहीं पता कि क्या कोई विहित तरीका है, लेकिन यहाँ मेरा तरीका है:

  • ViewController के लिए एक xib बनाएं
  • फ़ाइल स्वामी वर्ग को UIViewController पर सेट करें
  • दृश्य हटाएं और UITableViewCell जोड़ें
  • अपने कस्टम वर्ग के लिए अपने UITableViewCell की कक्षा निर्धारित करें
  • अपने UITableViewCell की पहचानकर्ता सेट करें
  • अपने दृश्य नियंत्रक दृश्य के आउटलेट को अपने UITableViewCell पर सेट करें

और इस कोड का उपयोग करें:

MyCustomViewCell *cell = (MyCustomViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
  UIViewController* c = [[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
  cell = (MyCustomViewCell *)c.view;
  [c release];
}

अपने उदाहरण में, का उपयोग करते हुए

[nib objectAtIndex:0]

अगर Apple जिब में वस्तुओं के क्रम में बदलाव करता है तो वह टूट सकता है।


मेरे लिए, यह हमेशा एक नई मिसाल पैदा करता है। लगता है हर बार शून्य लौट रहा है।
अजीब बात है

0
 NSString *CellIdentifier = [NSString stringWithFormat:@"cell %ld %ld",(long)indexPath.row,(long)indexPath.section];


    NewsFeedCell *cell = (NewsFeedCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    cell=nil;

    if (cell == nil)
    {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewsFeedCell" owner:nil options:nil];

        for(id currentObject in topLevelObjects)
        {
            if([currentObject isKindOfClass:[NewsFeedCell class]])
            {
                cell = (NewsFeedCell *)currentObject;
                break;
            }
        }
}
return cell;

0

इस एक्सटेंशन के लिए Xcode7 Beta6 की आवश्यकता होती है

extension NSBundle {
    enum LoadViewError: ErrorType {
        case ExpectedXibToExistButGotNil
        case ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        case XibReturnedWrongType
    }

    func loadView<T>(name: String) throws -> T {
        let topLevelObjects: [AnyObject]! = loadNibNamed(name, owner: self, options: nil)
        if topLevelObjects == nil {
            throw LoadViewError.ExpectedXibToExistButGotNil
        }
        if topLevelObjects.count != 1 {
            throw LoadViewError.ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        }
        let firstObject: AnyObject! = topLevelObjects.first
        guard let result = firstObject as? T else {
            throw LoadViewError.XibReturnedWrongType
        }
        return result
    }
}

एक Xib फ़ाइल बनाएं जिसमें सिर्फ 1 कस्टम UITableViewCell हो।

इसे लोड करें।

let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")

0
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cellReuseIdentifier = "collabCell"
            var cell:collabCell! = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? collabCell
            if cell == nil {
                tableView.register(UINib(nibName: "collabCell", bundle: nil), forCellReuseIdentifier: cellReuseIdentifier)
                cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! collabCell!
            }


            return cell

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