W jaki sposób załadować niestandardowe UITableViewCells z plików XIB?

głosy
278

Pytanie jest proste: Jak załadować niestandardowy UITableViewCellz plików XIB? Takie postępowanie pozwala na użycie interfejsu Builder do projektowania swoich komórek. Odpowiedź najwyraźniej nie jest prosta ze względu na kwestie zarządzania bazami pamięci. Wątek wymienia problem i proponuje rozwiązanie, ale jest wstępnie NDA uwalniania i nie ma kod. Oto długi wątek , który omawia kwestię bez podania ostatecznej odpowiedzi.

Oto niektóre kodu użyłem:

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

Aby użyć tego kodu, tworzenie MyCell.m / .h, nową podklasę UITableViewCelli dodać IBOutletsdo składników, które chcesz. Następnie należy utworzyć nową „Empty XIb” plik. Otwórz plik XIB w IB, dodaj UITableViewCellobiekt, ustaw swój identyfikator do „MyCellIdentifier” i ustawić jego klasę MyCell i dodać składniki. Wreszcie, należy podłączyć IBOutletsdo komponentów. Zauważ, że nie ustawić plik za właściciela w IB.

Inne metody zalecają ustawienie pliku Właścicielem i ostrzegają wycieków pamięci, jeśli XIb nie jest załadowany za pomocą dodatkowej klasy fabrycznej. I badano powyżej w instrumenty / Wycieki i nie widzi przecieków pamięci.

Więc co jest kanoniczny sposób załadować komórki przed Xibs? Czy możemy ustawić plik jest właścicielem? Czy potrzebujemy fabrykę? Jeśli tak, to jaki jest kod na fabryce wyglądać? Jeśli istnieje wiele rozwiązań, niech wyjaśnić zalety i wady każdego z nich ...

Utwórz 12/02/2009 o 08:27
źródło użytkownik
W innych językach...                            


23 odpowiedzi

głosy
292

Dobrym rozwiązaniem jest to:

- (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;
}
Odpowiedział 29/11/2012 o 16:57
źródło użytkownik

głosy
282

Oto dwa sposoby której pierwotne stany autorem był polecane przez inżyniera IB .

Zobaczyć rzeczywisty słupek więcej szczegółów. Wolę Sposób nr 2, jak się wydaje prostsze.

Sposób nr 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;
}

Sposób nr 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;
}

Update (2014): Metoda nr 2 jest nadal ważna, ale nie ma już dla niego dokumentacji. Kiedyś to było w oficjalnych docs , ale teraz jest usuwany za storyboardy.

Zamieściłem pracy przykład na Github:
https://github.com/bentford/NibTableCellExample

Odpowiedział 21/12/2009 o 11:19
źródło użytkownik

głosy
33

Zarejestrować

Po iOS 7, proces ten został uproszczony do ( szybkim 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")

( Uwaga ) Jest to również osiągalne poprzez tworzenie komórek w .xiblub .stroyboardplików, jak komórki prototypowych. Jeśli chcesz dołączyć klasę do nich, można wybrać prototyp komórki i dodać odpowiednią klasę (musi być potomkiem UITableViewCell, oczywiście).

rozkolejkowania

A później, rozkolejkowywana użyciu ( Swift 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
}

Z tą różnicą, że ta nowa metoda dequeues nie tylko komórkę, ale także tworzy jeśli nie istnial (co oznacza, że nie trzeba robić if (cell == nil)shenanigans), a komórka jest gotowy do użycia, tak jak w powyższym przykładzie.

( Ostrzeżenie ) tableView.dequeueReusableCell(withIdentifier:for:)ma nowe zachowanie, jeśli wywołać drugą (bez indexPath:) można uzyskać starego zachowania, w którym trzeba sprawdzić nili instancja samemu, zwróć uwagę na UITableViewCell?wartości zwracanej.

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

I oczywiście, typ skojarzonego klasy komórki jest tym, który zdefiniowany w pliku .xib dla UITableViewCellpodklasy, lub alternatywnie, stosując inną metodę rejestru.

Konfiguracja

Idealnie, twoje komórki zostały już skonfigurowane pod względem wyglądu i pozycjonowania zawartości (jak etykiety i poglądów obraz) w momencie ich rejestracji, a na cellForRowAtIndexPathmetodzie wystarczy wypełnić je.

Wszyscy razem

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

I oczywiście, to wszystko jest dostępne w ObjC o tych samych nazwach.

Odpowiedział 21/05/2015 o 01:47
źródło użytkownik

głosy
32

Wziął odpowiedź Shawn Craver i czyścić go trochę.

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

Robię wszystkie podklasy UITableViewCell mojego dnia BBCell, a następnie zastąpić standard

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

z:

cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];
Odpowiedział 22/06/2010 o 03:15
źródło użytkownik

głosy
15

Kiedyś bentford za Sposób nr 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;
}

To działa, ale uważaj na połączenia do pliku Właścicielem w niestandardowych UITableViewCell .xib pliku.

Przekazując owner:selfw swoim loadNibNamedoświadczeniu, zostanie ustawiony UITableViewControllerjako plik jest posiadaczem UITableViewCell.

Jeśli przeciągnij i upuść do pliku nagłówka w IB skonfigurować działania i zbytu, będzie je ustawić jako właściciel pliku jest domyślnie.

W loadNibNamed:owner:options, kod Apple będzie próbował ustawić właściwości na własną UITableViewController, ponieważ to właściciel. Ale nie masz te właściwości zdefiniowane tam, więc pojawi się błąd o byciu wartość klucza kodowania zgodny z :

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

Jeśli zdarzenie zostanie wywołane zamian dostaniesz 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

Prostym rozwiązaniem jest punkt połączeń Interfejs Builder Pod UITableViewCellWłaściciel zamiast pliku za:

  1. Kliknij prawym przyciskiem myszy na plik Właścicielem podciągnąć listę połączeń
  2. Zrób zrzut ekranu z Command-Shift-4 (przeciągnij, aby zaznaczyć obszar do niewoli)
  3. x out połączenia z właścicielem pliku jest
  4. Kliknij prawym przyciskiem myszy na UITableCell w hierarchii obiekt i ponownie dodać połączenia.
Odpowiedział 19/03/2012 o 22:41
źródło użytkownik

głosy
12

Zdecydowałem się pisać, ponieważ nie lubię żadnej z tych odpowiedzi - to wszystko może być zawsze bardziej proste i jest to zdecydowanie najbardziej zwięzły sposób znalazłem.

1. Zbuduj XIB w interfejsie Builder jak wam się podoba

  • Zawartość pliku za Właściciel do klasy NSObject
  • Dodaj UITableViewCell i ustawić tej klasy MyTableViewCellSubclass - w przypadku awarii IB (dzieje się w Xcode> 4 jak to pisze), wystarczy użyć UIView z interfejsu zrobić w Xcode 4, jeżeli nadal masz to około r
  • Układ Twoje subviews wewnątrz tej komórki i dołączyć połączeń IBOutlet do @interface w .h i .m (.m jest moje preferencje)

2. W swojej UIViewController lub UITableViewController podklasy

@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. W swoim MyTableViewCellSubclass

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

    return self;
}
Odpowiedział 26/08/2013 o 09:18
źródło użytkownik

głosy
8

Jeśli używasz interfejsu Builder, aby komórki, sprawdź czy masz ustawić identyfikator w inspektora. Następnie sprawdzić, czy to jest to samo, gdy dzwoni dequeueReusableCellWithIdentifier.

I przypadkowo zapomniał ustawić kilka identyfikatorów w projekcie tabeli ciężki, a zmiana wydajność była jak dzień i noc.

Odpowiedział 28/04/2010 o 11:55
źródło użytkownik

głosy
7

Ładowanie UITableViewCells z XIBs oszczędza dużo kodu, ale zwykle skutkuje strasznym prędkości przewijania (właściwie, to nie XIB ale nadmierne korzystanie z UIViews które powodują tego).

Proponuję spojrzeć na to: LINK

Odpowiedział 12/02/2009 o 15:19
źródło użytkownik

głosy
5

Oto metoda klasy, które używam do tworzenia własnych komórek z 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;
}

Następnie w XIB, ustawić nazwę klasy oraz identyfikator ponownego wykorzystania. Po tym, można po prostu wywołanie tej metody moim zdaniem regulatora zamiast

[[UITableViewCell] alloc] initWithFrame:]

Jest to wystarczająco szybko, i jest stosowany w dwóch moich zastosowań morskich. To bardziej niezawodny niż dzwonienie [nib objectAtIndex:0], a w głowie przynajmniej bardziej niezawodny niż np Stephana Burlot ponieważ masz gwarancję, aby tylko złapać widok na zewnątrz z XIB że stosowany jest odpowiedni rodzaj.

Odpowiedział 12/02/2009 o 14:47
źródło użytkownik

głosy
4

Rozwiązanie to jest poprawne

- (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; 
    }
Odpowiedział 07/09/2016 o 08:33
źródło użytkownik

głosy
3

Zaznacz to - http://eppz.eu/blog/custom-uitableview-cell/ - bardzo wygodny sposób za pomocą maleńką klasę, która kończy się o jedną linię w realizacji kontrolera:

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

wprowadzić opis obrazu tutaj

Odpowiedział 09/07/2013 o 10:18
źródło użytkownik

głosy
3

Przeładowywania Stalówka jest drogie. Lepiej załadować go raz, a następnie wystąpienia obiektów, kiedy trzeba komórkę. Pamiętaj, że możesz dodać UIImageViews etc do stalówki, nawet wiele komórek, przy użyciu tej metody (Apple „registerNIB” iOS5 pozwala tylko jeden przedmiot górny poziom - Błąd 10580062 „iOS5 tableView registerNib: zbyt restrykcyjna”

Więc mój kod jest poniżej - można przeczytać w NIB raz (w initialize jak ja lub w viewDidLoad -.. Cokolwiek Odtąd ty instancję stalówkę do obiektów następnie wybrać jeden trzeba ten jest o wiele bardziej wydajny niż ładowanie stalówkę raz po raz.

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;
}
Odpowiedział 14/12/2011 o 20:01
źródło użytkownik

głosy
2

Najpierw zaimportować plik zwyczaj komórek #import "CustomCell.h", a następnie zmienić metodę delegata jak niżej wymienione:

- (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;
}
Odpowiedział 26/02/2014 o 07:48
źródło użytkownik

głosy
2

Poprawny sposób to zrobić jest stworzenie implementacji podklasy UITableViewCell, nagłówek i XIb. W XIB usunąć wszelkie opinie i wystarczy dodać komórkę tabeli. Ustaw klasę jako nazwa podklasy UITableViewCell. Dla właściciela pliku, sprawiają, że nazwa UITableViewController klasa podklasa. Połączyć się z właścicielem pliku do komórki przy użyciu gniazdka tableViewCell.

W pliku nagłówka:

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

W pliku wdrażania:

@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;
}
Odpowiedział 28/06/2012 o 22:57
źródło użytkownik

głosy
2

Co zrobić, bo to jest zadeklarować IBOutlet UITableViewCell *cellw klasie kontrolera. Następnie wywołać NSBundle loadNibNamedmetodę klasy, które będą karmić UITableViewCelldo celi deklarowanej powyżej.

Dla XIb będę utworzyć pusty XIb i dodać UITableViewCellobiekt w IB, gdzie może być skonfigurowany według potrzeb. Pogląd ten jest następnie połączony z komórką IBOutletw klasie kontrolera.

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

dodatki NSBundle loadNibNamed (ADC logowania)

cocoawithlove.com artykuł I pozyskiwane pojęcia z (Pobierz aplikację numery telefonu próbki)

Odpowiedział 12/02/2009 o 19:01
źródło użytkownik

głosy
1

W Swift 4,2 i 10 Xcode

Mam trzy pliki komórkowych XIB

w viewDidLoad zarejestrować plików XIB tak ...

Jest to pierwsze podejście

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")

Drugie podejście bezpośrednio zarejestrować plików XIB w cellForRowAt indexPath:

To jest moje funkcje tableview delegata

//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
    }

}
Odpowiedział 12/10/2018 o 07:02
źródło użytkownik

głosy
1
  1. Stwórz własną dostosować klasy AbcViewCellpodklasy UITableViewCell(Upewnij się, że nazwa pliku klasy i nazwa pliku stalówka są takie same)

  2. Tworzenie tej metody klasy rozszerzenia.

    extension UITableViewCell {
        class func fromNib<T : UITableViewCell>() -> T {
            return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0] as! T
        }
    }
    
  3. Użyj tego.

    let cell: AbcViewCell = UITableViewCell.fromNib()

Odpowiedział 07/09/2017 o 04:07
źródło użytkownik

głosy
1

Nie wiem, czy istnieje kanoniczny sposób, ale tutaj jest moja metoda:

  • Tworzenie XIb dla ViewController
  • Ustaw klasę właściciel pliku do UIViewController
  • Usuń widok i dodaj UITableViewCell
  • Ustaw klasę swojej UITableViewCell do klasy niestandardowego
  • Ustaw identyfikator Twojej UITableViewCell
  • Ustaw wylot Państwa zdanie kontrolera widoku do UITableViewCell

I użyć tego kodu:

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

W przykładzie, stosując

[nib objectAtIndex:0]

może pęknąć jeśli Apple zmienia kolejność elementów w XIb.

Odpowiedział 12/02/2009 o 10:03
źródło użytkownik

głosy
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

}
Odpowiedział 18/05/2018 o 11:17
źródło użytkownik

głosy
0

Tutaj jest uniwersalnym podejściem do rejestracji komórek w 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)
    }
}

Wyjaśnienie:

  1. ReusableProtokół generuje identyfikator komórki, z nazwy klasy. Upewnij się, że zgodnie z konwencją: cell ID == class name == nib name.
  2. UITableViewCellzgodny z Reusableprotokołem.
  3. UITableView Rozszerzenie abstrahuje dala różnicę rejestracji komórek poprzez stalówki lub klasy.

Przykład użycia:

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
}
Odpowiedział 18/08/2017 o 08:08
źródło użytkownik

głosy
0

To rozszerzenie wymaga 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
    }
}

Utwórz plik XIb, który zawiera tylko 1 niestandardowego UITableViewCell.

Załaduj To.

let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")
Odpowiedział 28/08/2015 o 19:44
źródło użytkownik

głosy
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;
Odpowiedział 11/06/2014 o 07:38
źródło użytkownik

głosy
0

Oto mój sposób, że: Ładowanie niestandardowy UITableViewCells z XIB pliki ... Jeszcze inna metoda

Ideą jest stworzenie SampleCell podklasą UITableViewCellz IBOutlet UIView *contentwłasności i właściwości dla każdego zwyczaju subview trzeba skonfigurować z kodu. Następnie utworzyć plik SampleCell.xib. W tym pliku nib, zmienić właściciela pliku na SampleCell. Dodaj zawartość UIViewrozmiarze do swoich potrzeb. Dodawać i konfigurować wszystkie subviews (etykieta, wyświetlenia obrazu, przyciski itp) chcesz. Wreszcie odwołuje pogląd treści i subviews do właściciela pliku.

Odpowiedział 24/03/2011 o 12:51
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more