Chargement d’un UITableViewCell réutilisable à partir d’un Nib

Je suis en mesure de concevoir des UITableViewCells personnalisés et de les charger à l’aide de la technique décrite dans la discussion disponible à l’ adresse http://forums.macrumors.com/showthread.php?t=545061 . Cependant, l’utilisation de cette méthode ne vous permet plus d’initialiser la cellule avec un identifiant de réutilisation, ce qui signifie que vous devez créer de nouvelles instances complètes de chaque cellule à chaque appel. Quelqu’un a-t-il trouvé un bon moyen de mettre en cache des types de cellules particuliers pour les réutiliser, tout en étant capable de les concevoir dans Interface Builder?

Implémentez simplement une méthode avec la signature de méthode appropriée:

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

En fait, puisque vous créez la cellule dans Interface Builder, définissez simplement l’identificateur de réutilisation:

IB_reuse_identifier

Ou, si vous exécutez Xcode 4, cochez l’onglet Inspecteur d’atsortingbuts:

entrer la description de l'image ici

(Edit: une fois que XIB est généré par XCode, il contient un UIView vide, mais nous avons besoin d’un UITableViewCell; vous devez donc supprimer manuellement UIView et insérer une cellule de vue de table. Bien sûr, IB ne présentera aucun paramètre UITableViewCell pour une UIView.)

Maintenant, dans iOS 5, il existe une méthode UITableView appropriée pour cela:

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

Je ne me souviens plus où j’ai trouvé ce code à l’origine, mais ça a fonctionné très bien pour moi jusqu’à présent.

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSSsortingng *CellIdentifier = @"CustomTableCell"; static NSSsortingng *CellNib = @"CustomTableCellView"; UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil]; cell = (UITableViewCell *)[nib objectAtIndex:0]; } // perform additional custom work... return cell; } 

Exemple de configuration d’Interface Builder …

alt text http://i32.tinypic.com/a9mnap.jpg

Regardez la réponse que j’ai donnée à cette question:

Est-il possible de concevoir des sous-classes NSCell dans Interface Builder?

Il est non seulement possible de concevoir un UITableViewCell dans IB, mais cela est souhaitable car sinon tout le câblage manuel et le placement de plusieurs éléments sont très fastidieux. La performance est correcte tant que vous veillez à rendre tous les éléments opaques lorsque cela est possible. L’identifiant de réutilisation est défini dans IB pour les propriétés de UITableViewCell, puis vous utilisez l’identifiant de réutilisation correspondant dans le code lorsque vous tentez de retirer la queue.

L’année dernière, certains des présentateurs de la WWDC ont également déclaré que vous ne devriez pas créer de cellules de vue de table dans IB, mais que ce serait une charge énorme.

À partir d’iOS circa 4.0, il existe des instructions spécifiques dans les documents iOS qui rendent ce travail extrêmement rapide:

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

Faites défiler jusqu’à l’endroit où il est question de sous-classer UITableViewCell.

Voici une autre option:

 NSSsortingng * cellId = @"reuseCell"; //... NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil]; for (id obj in nibObjects) { if ([obj isKindOfClass:[CustomTableCell class]]) { cell = obj; [cell setValue:cellId forKey:@"reuseIdentifier"]; break; } } 

Je crée mes cellules d’affichage personnalisées d’une manière similaire – sauf que je connecte la cellule via un IBOutlet.

L’approche [nib objectAt...] est susceptible de changer les positions des éléments du tableau.

L’approche UIViewController est bonne – il suffit de l’essayer, et cela fonctionne assez bien.

MAIS…

Dans tous les cas, le constructeur initWithStyle n’est PAS appelé, donc aucune initialisation par défaut n’est effectuée.

J’ai lu divers endroits sur l’utilisation de initWithCoder ou awakeFromNib , mais aucune preuve concluante que l’un ou l’autre est le bon moyen.

Outre l’appel explicite d’une méthode d’initialisation dans la méthode cellForRowAtIndexPath , je n’ai pas encore trouvé de réponse à cette question.

Il y a quelque temps, j’ai trouvé un excellent article sur ce sujet sur blog.atebits.com , et depuis, j’ai commencé à utiliser la classe ABTableViewCell de Loren Brichter pour faire tous mes UITableViewCells.

Vous vous retrouvez avec un conteneur UIView simple pour mettre tous vos widgets, et le défilement est rapide comme l’éclair.

J’espère que c’est utile.

Cette technique fonctionne également et ne nécessite pas un ivar funky dans votre contrôleur de vue pour la gestion de la mémoire. Ici, la cellule de vue de table personnalisée se trouve dans un fichier xib nommé “CustomCell.xib”.

  static NSData *sLoadedCustomCell = nil; cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"]; if (cell == nil) { if (sLoadedCustomCell == nil) { // Load the custom table cell xib // and extract a reference to the cell object returned // and cache it in a static to avoid reloading the nib again. for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) { if ([loadedObject isKindOfClass:[UITableViewCell class]]) { sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain]; break; } } cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell]; } 

La méthode de Louis a fonctionné pour moi. C’est le code que j’utilise pour créer le UITableViewCell à partir du nib:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"]; if (cell == nil) { UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil]; cell = (PostCell *)c.view; [c release]; } return cell; } 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSSsortingng *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; } 

La solution gustavogb ne fonctionne pas pour moi, j’ai essayé:

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

Cela semble fonctionner. Le blogTableViewCell est l’IBOutlet de la cellule et ChainesController est le propriétaire du fichier.

À partir des documents UITableView concernant dequeueWithReuseIdentifier : “Chaîne identifiant l’object de cellule à réutiliser. Par défaut, l’identificateur d’une cellule réutilisable est son nom de classe, mais vous pouvez le modifier en n’importe quelle valeur arbitraire.”

Ignorer -reuseIdentifer est risqué. Que se passe-t-il si vous avez deux sous-classes de votre sous-classe de cellules et que vous les utilisez toutes les deux dans une seule vue de table? S’ils envoient l’appel de l’identifiant de réutilisation sur super, vous dépouillerez une cellule du mauvais type ………….. Je pense que vous avez besoin de remplacer la méthode reuseIdentifier, mais qu’elle renvoie un identifiant supplanté chaîne. Ou, s’il n’en a pas été spécifié, demandez-lui de renvoyer la classe sous forme de chaîne.

Pour ce que cela vaut, j’ai interrogé un ingénieur iPhone à ce sujet lors d’une conférence technique sur iPhone. Sa réponse était: “Oui, il est possible d’utiliser IB pour créer des cellules. Mais ne le faites pas. S’il vous plaît, ne le faites pas.”

J’ai suivi les instructions d’Apple liées par Ben Mosher (merci!) Mais j’ai trouvé qu’Apple avait omis un point important. L’object qu’ils conçoivent dans IB n’est qu’un object UITableViewCell, tout comme la variable qu’ils en chargent. Mais si vous le configurez en tant que sous-classe personnalisée de UITableViewCell et que vous écrivez les fichiers de code pour la sous-classe, vous pouvez écrire des déclarations IBOutlet et des méthodes IBAction dans le code et les connecter à vos éléments personnalisés dans IB. Il n’est alors pas nécessaire d’utiliser les balises de vue pour accéder à ces éléments et vous pouvez créer tout type de cellule fou que vous souhaitez. C’est le cacao touche le paradis.