La question est simple: comment charger une variable UITableViewCell
personnalisée à partir de fichiers Xib? Cela vous permet d'utiliser Interface Builder pour concevoir vos cellules. La réponse n’est apparemment pas simple en raison de problèmes de gestion de la mémoire. Ce fil de discussion mentionne le problème et suggère une solution, mais il s'agit d'une version antérieure à la publication de la NDA et manquant de code. Voici un fil long qui traite du problème sans fournir de réponse définitive.
Voici du code que j'ai utilisé:
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];
}
Pour utiliser ce code, créez MyCell.m/.h, une nouvelle sous-classe de UITableViewCell
et ajoutez IBOutlets
pour les composants souhaités. Créez ensuite un nouveau fichier "XIB vide". Ouvrez le fichier Xib dans IB, ajoutez un objet UITableViewCell
, définissez son identificateur sur "MyCellIdentifier", définissez sa classe sur MyCell et ajoutez vos composants. Enfin, connectez la IBOutlets
aux composants. Notez que nous n'avons pas défini le propriétaire du fichier dans IB.
D'autres méthodes préconisent de définir le propriétaire du fichier et d'avertir les fuites de mémoire si le fichier Xib n'est pas chargé via une classe d'usine supplémentaire. J'ai testé ce qui précède sous Instruments/Fuites et je n'ai constaté aucune fuite de mémoire.
Alors, quel est le moyen canonique de charger des cellules à partir de Xibs? Définissons-nous le propriétaire du fichier? Avons-nous besoin d'une usine? Si tel est le cas, à quoi ressemble le code de l'usine? S'il existe plusieurs solutions, clarifions le pour et le contre de chacune d'entre elles ...
Voici deux méthodes pour lesquelles l'auteur original a été recommandé par un ingénieur de l'IB .
Voir le post actuel pour plus de détails. Je préfère la méthode n ° 2 car cela semble plus simple.
Méthode n ° 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;
}
Méthode n ° 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): La méthode n ° 2 est toujours valide mais il n'y a plus de documentation à ce sujet. Il était jadis dans la documentation officielle mais est maintenant supprimé au profit des storyboards.
J'ai posté un exemple de travail sur Github:
https://github.com/bentford/NibTableCellExample
La bonne solution est la suivante:
- (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;
}
Après iOS 7, ce processus a été simplifié jusqu'à ( Swift 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")
( Remarque ) Ceci est également réalisable en créant les cellules dans les fichiers
.xib
ou.stroyboard
, en tant que cellules prototypes . Si vous devez y attacher une classe, vous pouvez sélectionner le prototype de cellule et ajouter la classe correspondante (il faut bien entendu être un descendant deUITableViewCell
).
Et plus tard, retiré de la file d'attente en utilisant ( 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
}
La différence est que cette nouvelle méthode non seulement met la cellule en file d'attente, mais qu'elle est également inexistante (cela signifie que vous n'avez pas à faire if (cell == nil)
shenanigans) et que la cellule est prête à être utilisée comme dans l'exemple ci-dessus.
( Warning )
tableView.dequeueReusableCell(withIdentifier:for:)
a le nouveau comportement. Si vous appelez l’autre (sansindexPath:
), vous obtenez l’ancien comportement dans lequel vous devez recherchernil
et l’instruire vous-même, notez la valeur renvoyéeUITableViewCell?
.
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCellClass
{
// Cell be casted properly
cell.myCustomProperty = true
}
else
{
// Wrong type? Wrong identifier?
}
Et bien sûr, le type de la classe associée à la cellule est celui que vous avez défini dans le fichier .xib pour la sous-classe UITableViewCell
ou bien en utilisant l’autre méthode de registre.
Idéalement, vos cellules ont déjà été configurées en termes d’apparence et de positionnement du contenu (telles que les étiquettes et les vues d’image) au moment où vous les avez enregistrées, et vous les remplissez simplement avec la méthode 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
}
}
Et bien sûr, tout cela est disponible dans ObjC avec les mêmes noms.
A pris la réponse de Shawn Craver et nettoyé un peu.
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
Je crée toutes les sous-classes de BBCell de mes UITableViewCell, puis je remplace la norme
cell = [[[BBDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BBDetailCell"] autorelease];
avec:
cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];
J'ai utilisé bentford's Méthode n ° 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;
}
Cela fonctionne, mais faites attention aux connexions au propriétaire de File dans votre fichier .xib UITableViewCell personnalisé.
En passant owner:self
dans votre instruction loadNibNamed
, vous définissez UITableViewController
en tant que propriétaire du fichier de votre UITableViewCell
.
Si vous faites glisser et déposez le fichier d'en-tête dans IB pour configurer des actions et des prises, il les définira par défaut comme propriétaire du fichier.
Dans loadNibNamed:owner:options
, le code d'Apple essaiera de définir les propriétés de votre UITableViewController
, puisque c'est le propriétaire. Mais ces propriétés ne sont pas définies ici. Vous obtenez donc une erreur indiquant que vous êtes conforme à la codification key value:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MyUITableViewController 0x6a383b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key myLabel.'
Si un événement est déclenché à la place, vous obtiendrez une 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
Une solution de contournement simple consiste à pointer vos connexions Interface Builder sur la variable UITableViewCell
au lieu de Propriétaire du fichier:
J'ai décidé de poster car je n'aime aucune de ces réponses - les choses peuvent toujours être plus simples et c'est de loin le moyen le plus concis que j'ai trouvé.
1. Construisez votre Xib dans Interface Builder à votre guise
2. Dans votre sous-classe UIViewController ou 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. Dans votre MyTableViewCellSubclass
- (id) initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
...
}
return self;
}
Si vous utilisez Interface Builder pour créer des cellules, vérifiez que vous avez défini l'identifiant dans l'inspecteur. Ensuite, vérifiez qu'il en va de même lorsque vous appelez dequeueReusableCellWithIdentifier.
J'ai accidentellement oublié de définir des identifiants dans un projet contenant beaucoup de tables et le changement de performances ressemblait à un jour et une nuit.
Charger UITableViewCells à partir de XIBs économise beaucoup de code, mais entraîne généralement une vitesse de défilement horrible (en fait, ce n'est pas le XIB mais l'utilisation excessive d'UIViews qui en est la cause).
Je vous suggère de jeter un coup d'oeil à ceci: Référence du lien
Voici la méthode de classe que j'utilise pour créer des cellules personnalisées à partir de XIB:
+ (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;
}
Ensuite, dans le fichier XIB, j'ai défini le nom de la classe et l'identificateur de réutilisation. Après cela, je peux simplement appeler cette méthode dans mon contrôleur de vue au lieu de la
[[UITableViewCell] alloc] initWithFrame:]
Il est assez rapide et utilisé dans deux de mes applications d’expédition. C'est plus fiable que d'appeler [nib objectAtIndex:0]
, et du moins dans mon esprit, plus fiable que l'exemple de Stephan Burlot, car vous êtes assuré de n'obtenir que la vue d'un fichier XIB du bon type.
La solution correcte est-ce
- (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;
}
Vérifiez ceci - http://eppz.eu/blog/custom-uitableview-cell/ - de manière vraiment pratique en utilisant une petite classe qui aboutit à une ligne dans l'implémentation du contrôleur:
-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
return [TCItemCell cellForTableView:tableView
atIndexPath:indexPath
withModelSource:self];
}
Recharger la carte NIB coûte cher. Mieux vaut le charger une fois, puis instancier les objets lorsque vous avez besoin d’une cellule. Notez que vous pouvez ajouter UIImageViews, etc., au nib, même à plusieurs cellules, en utilisant cette méthode (le "registerNIB" d’Apple ne permet qu’un seul objet de niveau supérieur - le bogue 10580062 ". IOS5 tableView registerNib: trop restrictif"
Donc mon code est en dessous - vous lisez une fois dans le NIB (en initialisant comme moi ou dans viewDidload - peu importe. Ensuite, vous instanciez le nib en objets puis en sélectionnant celui dont vous avez besoin. C'est beaucoup plus efficace que de charger le nib encore et encore.
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;
}
La bonne façon de le faire est de créer une implémentation de sous-classe UITableViewCell, un en-tête et XIB. Dans XIB, supprimez toutes les vues et ajoutez simplement une cellule de tableau. Définissez la classe comme nom de la sous-classe UITableViewCell. Pour le propriétaire du fichier, indiquez le nom de la classe de la sous-classe UITableViewController. Connectez le propriétaire du fichier à la cellule à l'aide de la sortie tableViewView.
Dans le fichier d'en-tête:
UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;
Dans le fichier d'implémentation:
@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;
}
Pour ce faire, je déclare un IBOutlet UITableViewCell *cell
dans votre classe de contrôleur . Ensuite, appelez la méthode de la classe NSBundle loadNibNamed
, qui alimentera la UITableViewCell
dans la cellule déclarée ci-dessus.
Pour xib, je vais créer un xib vide et ajouter l'objet UITableViewCell
dans IB où il peut être configuré selon les besoins. Cette vue est ensuite connectée à la cellule IBOutlet
dans la classe de contrôleur.
- (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;
}
Commencez par importer votre fichier de cellule personnalisé #import "CustomCell.h"
, puis modifiez la méthode de délégué comme indiqué ci-dessous:
- (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;
}
Voici une approche universelle pour l'enregistrement de cellules dans 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)
}
}
Explication:
Reusable
génère l'ID de cellule à partir de son nom de classe. Assurez-vous de suivre la convention: cell ID == class name == nib name
.UITableViewCell
est conforme au protocole Reusable
.UITableView
résume la différence d'enregistrement de cellules via nib ou class.Exemple d'utilisation:
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
}
Dans Swift 4.2 et Xcode 10
J'ai trois fichiers de cellules XIB
dans ViewDidLoad, enregistrez vos fichiers XIB comme ceci ...
C'est la première approche
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")
La deuxième approche enregistre directement les fichiers XIB dans cellForRowAt indexPath:
Ce sont mes fonctions de délégué 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
}
}
Voici ma méthode pour cela: Chargement de UITableViewCells personnalisés à partir de fichiers XIB… Encore une autre méthode
L'idée est de créer une sous-classe SampleCell de UITableViewCell
avec une propriété IBOutlet UIView *content
et une propriété pour chaque sous-vue personnalisée à configurer à partir du code. Ensuite, créez un fichier SampleCell.xib. Dans ce fichier nib, changez le propriétaire du fichier en SampleCell. Ajoutez un contenu UIView
de taille adaptée à vos besoins. Ajoutez et configurez toutes les sous-vues (étiquette, vues d'image, boutons, etc.) souhaitées. Enfin, liez la vue du contenu et les sous-vues au propriétaire du fichier.
Je ne sais pas s'il existe un moyen canonique, mais voici ma méthode:
Et utilisez ce code:
MyCustomViewCell *cell = (MyCustomViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
UIViewController* c = [[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
cell = (MyCustomViewCell *)c.view;
[c release];
}
Dans votre exemple, en utilisant
[nib objectAtIndex:0]
peut se rompre si Apple modifie l'ordre des éléments dans la xib.
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
}
Cette extension nécessite 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
}
}
Créez un fichier Xib contenant seulement 1 UITableViewCell personnalisé.
Charge le.
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;