Die Frage ist einfach: Wie lädt man benutzerdefinierte UITableViewCell
aus Xib-Dateien? Auf diese Weise können Sie Interface Builder verwenden, um Ihre Zellen zu entwerfen. Die Antwort ist anscheinend aufgrund von Problemen beim Speichermanagement nicht einfach. Dieser Thread erwähnt das Problem und schlägt eine Lösung vor, ist jedoch vor der NDA-Veröffentlichung und hat keinen Code. Hier ist ein langer Thread , der das Thema diskutiert, ohne eine endgültige Antwort zu geben.
Hier ist ein Code, den ich verwendet habe:
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];
}
Erstellen Sie zur Verwendung dieses Codes MyCell.m/.h, eine neue Unterklasse von UITableViewCell
, und fügen Sie IBOutlets
für die gewünschten Komponenten hinzu. Erstellen Sie dann eine neue "Empty XIB" -Datei. Öffnen Sie die Xib-Datei in IB, fügen Sie ein UITableViewCell
-Objekt hinzu, setzen Sie den Bezeichner auf "MyCellIdentifier" und die Klasse auf MyCell, und fügen Sie Ihre Komponenten hinzu. Verbinden Sie schließlich die IBOutlets
mit den Komponenten. Beachten Sie, dass wir den Eigentümer der Datei in IB nicht festgelegt haben.
Andere Methoden sprechen sich dafür aus, den Besitzer der Datei festzulegen, und warnen vor Speicherverlusten, wenn Xib nicht über eine zusätzliche Factory-Klasse geladen wird. Ich habe das oben unter Instruments/Leaks getestet und sah keine Speicherlecks.
Was ist der kanonische Weg, Zellen aus Xibs zu laden? Setzen wir den Besitzer der Datei? Brauchen wir eine Fabrik? Wenn ja, wie sieht der Code für die Fabrik aus? Wenn es mehrere Lösungen gibt, lassen Sie uns die Vor- und Nachteile der einzelnen Lösungen klären ...
Hier sind zwei Methoden, die der Originalautor von einem IB-Ingenieur empfohlen hat .
Siehe den aktuellen Beitrag für weitere Details. Ich bevorzuge Methode Nr. 2, da dies einfacher erscheint.
Methode 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;
}
Methode 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): Methode Nr. 2 ist noch gültig, es ist jedoch keine Dokumentation mehr vorhanden. Früher befand es sich in den offiziellen Dokumenten , wird aber jetzt zugunsten von Storyboards entfernt.
Ich habe ein funktionierendes Beispiel auf Github veröffentlicht:
https://github.com/bentford/NibTableCellExample
Die richtige Lösung ist folgende:
- (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;
}
Nach iOS 7 wurde dieser Vorgang auf ( Swift 3.0 ) vereinfacht:
// For registering nib files
tableView.register(UINib(nibName: "MyCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")
// For registering classes
tableView.register(MyCellClass.self, forCellReuseIdentifier: "cell")
( Hinweis ) Dies ist auch durch das Erstellen der Zellen in den
.xib
- oder.stroyboard
-Dateien als Prototypzellen ..__ möglich. Wenn Sie ihnen eine Klasse zuordnen möchten, können Sie den Prototyp der Zelle auswählen und die entsprechende Klasse hinzufügen (muss natürlich ein Nachkomme vonUITableViewCell
sein).
Und später mit ( Swift 3.0 ) entschlüsselt:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Hello"
return cell
}
Der Unterschied besteht darin, dass diese neue Methode die Zelle nicht nur in eine Warteschlange stellt, sondern auch erstellt, wenn sie nicht existiert (dh, dass Sie keine if (cell == nil)
shenanigans durchführen müssen) und die Zelle wie im obigen Beispiel verwendet werden kann.
( Warning )
tableView.dequeueReusableCell(withIdentifier:for:)
hat das neue Verhalten. Wenn Sie das andere aufrufen (ohneindexPath:
), erhalten Sie das alte Verhalten, in dem Sie nachnil
suchen und es selbst instanzieren müssen. Beachten Sie den RückgabewertUITableViewCell?
.
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCellClass
{
// Cell be casted properly
cell.myCustomProperty = true
}
else
{
// Wrong type? Wrong identifier?
}
Natürlich ist der Typ der zugehörigen Klasse der Zelle der, den Sie in der .xib-Datei für die Unterklasse UITableViewCell
definiert haben, oder alternativ die andere Registermethode.
Idealerweise wurden Ihre Zellen bereits zum Zeitpunkt der Registrierung hinsichtlich Erscheinungsbild und Inhaltspositionierung (wie Beschriftungen und Bildansichten) konfiguriert. Bei der cellForRowAtIndexPath
-Methode füllen Sie sie einfach aus.
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
}
}
Und natürlich ist das alles in ObjC mit den gleichen Namen verfügbar.
Nahm Shawn Cravers Antwort und räumte ein bisschen auf.
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
Ich mache alle meine UITableViewCell-Unterklassen von BBCell und ersetze dann den Standard
cell = [[[BBDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BBDetailCell"] autorelease];
mit:
cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];
Ich habe Bentfords Methode # 2 verwendet:
- (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;
}
Es funktioniert, aber achten Sie auf Verbindungen zu File's Owner in Ihrer benutzerdefinierten UITableViewCell-.xib-Datei.
Durch Übergeben von owner:self
in Ihrer loadNibNamed
-Anweisung legen Sie die UITableViewController
als Dateieigentümer Ihrer UITableViewCell
fest.
Wenn Sie in IB die Header-Datei ziehen und ablegen, um Aktionen und Ausgänge festzulegen, werden diese standardmäßig als Eigentümer der Datei festgelegt.
In loadNibNamed:owner:options
versucht Apples Code, Eigenschaften für Ihre UITableViewController
festzulegen, da dies der Besitzer ist. Da diese Eigenschaften jedoch nicht definiert sind, wird eine Fehlermeldung angezeigt, dass Schlüsselwertcodierungskompatibel ist:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MyUITableViewController 0x6a383b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key myLabel.'
Wenn stattdessen ein Ereignis ausgelöst wird, erhalten Sie eine 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
Eine einfache Problemumgehung besteht darin, Ihre Interface Builder-Verbindungen auf die UITableViewCell
statt auf den Besitzer der Datei zu verweisen:
Ich habe mich entschlossen zu posten, da ich keine dieser Antworten mag - Dinge können immer einfacher sein und dies ist bei weitem der prägnanteste Weg, den ich gefunden habe.
1. Baue dein Xib im Interface Builder nach Belieben
2. In Ihrer UIViewController- oder UITableViewController-Unterklasse
@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. In Ihrer MyTableViewCellSubclass
- (id) initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
...
}
return self;
}
Wenn Sie den Interface Builder zum Erstellen von Zellen verwenden, überprüfen Sie, ob Sie im Inspector den Bezeichner festgelegt haben. Stellen Sie dann sicher, dass dies beim Aufruf von dequeueReusableCellWithIdentifier der Fall ist.
Ich habe versehentlich vergessen, einige Kennungen in einem tischlastigen Projekt festzulegen, und die Leistungsänderung war wie Tag und Nacht.
Beim Laden von UITableViewCells aus XIBs wird zwar viel Code gespeichert, dies führt jedoch in der Regel zu einer fürchterlichen Bildlaufgeschwindigkeit (eigentlich ist es nicht die XIB, sondern die übermäßige Verwendung von UIViews, die dies verursacht).
Ich schlage vor, Sie schauen sich das an: Linkverweis
Hier ist die Klassenmethode, die ich zum Erstellen von benutzerdefinierten Zellen aus XIBs verwendet habe:
+ (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;
}
Dann stelle ich in der XIB den Klassennamen ein und verwende die Kennung erneut. Danach kann ich diese Methode einfach in meinem View-Controller anstelle von aufrufen
[[UITableViewCell] alloc] initWithFrame:]
Es ist viel schnell genug und wird in zwei meiner Versandanwendungen verwendet. Es ist zuverlässiger als das Aufrufen von [nib objectAtIndex:0]
und zumindest meines Erachtens zuverlässiger als das von Stephan Burlot, da Sie sicher sind, dass Sie nur einen Blick auf eine XIB werfen, die der richtige ist.
Richtige Lösung ist das
- (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;
}
Überprüfen Sie diesen - http://eppz.eu/blog/custom-uitableview-cell/ - wirklich bequemen Weg mit einer winzigen Klasse, die in der Controller-Implementierung eine Zeile endet:
-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
return [TCItemCell cellForTableView:tableView
atIndexPath:indexPath
withModelSource:self];
}
Das Nachladen der NIB ist teuer. Laden Sie sie lieber einmal, und instanziieren Sie die Objekte, wenn Sie eine Zelle benötigen. Beachten Sie, dass Sie mit dieser Methode UIImageViews usw. zur Spitze (auch mehrere Zellen) hinzufügen können (Apples "registerNIB" iOS5 lässt nur ein Objekt der obersten Ebene zu - Bug 10580062 "IOS5 tableView registerNib: zu restriktiv)
Mein Code ist also unten - Sie lesen einmal in der NIB (in initialize wie bei mir oder in viewDidload - was auch immer. Von da an instantiieren Sie die Spitze in Objekte und wählen dann die gewünschte aus. Dies ist viel effizienter als das Laden der Spitze über und über.
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;
}
Der richtige Weg ist das Erstellen einer UITableViewCell-Unterklassenimplementierung, eines Headers und einer XIB. Entfernen Sie in der XIB alle Ansichten und fügen Sie einfach eine Tabellenzelle hinzu. Legen Sie die Klasse als Namen der UITableViewCell-Unterklasse fest. Geben Sie für den Dateieigner den Namen der UITableViewController-Unterklasse an. Verbinden Sie den Dateibesitzer über den tableViewCell-Ausgang mit der Zelle.
In der Headerdatei:
UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;
In der Implementierungsdatei:
@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;
}
Was ich dazu mache, ist das Deklarieren eines IBOutlet UITableViewCell *cell
in Ihrer Controller-Klasse . Dann rufen Sie die NSBundle loadNibNamed
-Klassenmethode auf, die die UITableViewCell
der oben deklarierten Zelle zuführt.
Für das xib werde ich ein leeres xib erstellen und das UITableViewCell
-Objekt in IB hinzufügen, wo es nach Bedarf eingerichtet werden kann. Diese Ansicht wird dann mit der Zelle IBOutlet
in der Controller-Klasse verbunden.
- (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-Ergänzungen loadNibNamed (ADC-Login)
cocoawithlove.com Artikel Ich habe das Konzept von (Beispiel-App für Telefonnummern) bezogen
Importieren Sie zuerst Ihre benutzerdefinierte Zellendatei #import "CustomCell.h"
und ändern Sie dann die Delegatmethode wie folgt:
- (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;
}
Erstellen Sie Ihre eigene angepasste Klasse AbcViewCell
Unterklasse aus UITableViewCell
(Stellen Sie sicher, dass der Name der Klassendatei und der Name der NIB-Datei identisch sind.)
Erstellen Sie diese Erweiterungsklassenmethode.
extension UITableViewCell {
class func fromNib<T : UITableViewCell>() -> T {
return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0] as! T
}
}
Benutze es.
let cell: AbcViewCell = UITableViewCell.fromNib()
Hier ist ein universeller Ansatz zum Registrieren von Zellen in 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)
}
}
Erläuterung:
Reusable
-Protokoll generiert die Zellen-ID aus dem Klassennamen. Stellen Sie sicher, dass Sie der Konvention folgen: cell ID == class name == nib name
.UITableViewCell
entspricht dem Reusable
-Protokoll.UITableView
beseitigt den Unterschied bei der Registrierung von Zellen über Spitze oder Klasse.Anwendungsbeispiel:
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
}
In Swift 4.2 und Xcode 10
Ich habe drei XIB-Zelldateien
registrieren Sie Ihre XIB-Dateien in ViewDidLoad wie folgt ...
Dies ist der erste Ansatz
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")
Zweiter Ansatz: Registrieren Sie XIB-Dateien direkt in cellForRowAt indexPath:
Dies ist meine Delegierungsfunktion für TableView
//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
}
}
Hier ist meine Methode dafür: Benutzerdefinierte UITableViewCells aus XIB-Dateien laden… Noch eine Methode
Die Idee ist, eine SampleCell-Unterklasse der UITableViewCell
mit einer IBOutlet UIView *content
-Eigenschaft und einer Eigenschaft für jede benutzerdefinierte Untersicht zu erstellen, die Sie aus dem Code konfigurieren müssen. Dann erstellen Sie eine SampleCell.xib-Datei. Ändern Sie in dieser Nib-Datei den Besitzer der Datei in SampleCell. Fügen Sie einen Inhalt UIView
hinzu, dessen Größe Ihren Anforderungen entspricht. Fügen Sie alle gewünschten Unteransichten (Beschriftungen, Bildansichten, Schaltflächen usw.) hinzu und konfigurieren Sie sie. Verknüpfen Sie schließlich die Inhaltsansicht und die Unteransichten mit dem Dateieigentümer.
Ich weiß nicht, ob es einen kanonischen Weg gibt, aber hier ist meine Methode:
Und benutze diesen Code:
MyCustomViewCell *cell = (MyCustomViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
UIViewController* c = [[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
cell = (MyCustomViewCell *)c.view;
[c release];
}
In Ihrem Beispiel verwenden Sie
[nib objectAtIndex:0]
kann beschädigt werden, wenn Apple die Reihenfolge der Elemente im Xib ändert.
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
}
Diese Erweiterung erfordert 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
}
}
Erstellen Sie eine Xib-Datei, die nur 1 benutzerdefinierte UITableViewCell enthält.
Lade es.
let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")
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;