web-dev-qa-db-fra.com

Chargement d'une UITableViewCell réutilisable à partir d'une nib

Je suis en mesure de concevoir des UITableViewCells personnalisées et de les charger correctement à l'aide de la technique décrite dans le fil de discussion trouvé à l'adresse http://forums.macrumors.com/showthread.php?t=545061 . Cependant, l'utilisation de cette méthode ne vous permet plus d'initier la cellule avec un identificateur reuseIdentifier, ce qui signifie que vous devez créer de toutes nouvelles instances de chaque cellule à chaque appel. Quelqu'un a-t-il trouvé un bon moyen de mettre en cache des types de cellules particuliers à des fins de réutilisation, tout en pouvant néanmoins les concevoir dans Interface Builder?

89
Greg Martin

Il suffit de mettre en œuvre une méthode avec la signature de méthode appropriée:

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}
74
Louis Gerbarg

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

IB_reuse_identifier

Ou, si vous utilisez Xcode 4, vérifiez l’onglet Inspecteur Attributs:

enter image description here

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

119
Tim Keating

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

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
66
wzs

Je ne me souviens pas de l'endroit où j'ai trouvé ce code à l'origine, mais cela fonctionne très bien pour moi jusqu'à présent.

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *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

47
jrainbow

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 une UITableViewCell dans IB, mais il est également souhaitable, car sinon, tout le câblage manuel et le placement de plusieurs éléments sont très fastidieux. Performaance est acceptable si vous prenez soin de rendre tous les éléments opaques lorsque cela est possible. Le code de réutilisation est défini dans IB pour les propriétés de UITableViewCell. Vous utilisez ensuite le code de réutilisation correspondant dans le code lors d'une tentative de suppression de la file d'attente.

L’année dernière, des conférenciers de la WWDC ont également fait savoir qu’il ne fallait pas créer de cellules d’affichage de tableaux dans IB, mais que c’était un fardeau.

Depuis la version 4.0 d’iOS, il existe des instructions spécifiques dans la documentation iOS qui rendent cette opération 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-classe UITableViewCell.

7
Ben Mosher

Voici une autre option:

NSString * 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;
    }
}
6
JDL

Cette technique fonctionne également et ne nécessite pas d’ivar funky dans votre contrôleur de vue pour la gestion de la mémoire. Ici, la cellule de vue de tableau personnalisée réside 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];
  }
2
Bill Garrison

Je crée mes cellules de vue personnalisées de la même manière, sauf que je la connecte via un IBOutlet.

Le [nib objectAt...] L'approche est susceptible de changer la position des éléments du tableau.

L'approche UIViewController est bonne - je l'ai juste essayée et elle fonctionne assez bien.

MAIS...

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

J'ai lu divers endroits sur l'utilisation de initWithCoder ou awakeFromNib, mais je n'ai aucune preuve concluante que l'un ou l'autre est la bonne manière.

Mis à part 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.

2
sww

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

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

J'espère que c'est utile.

2
eric
- (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
Mohit

La méthode 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;
}
2
ggarber

La solution gustavogb ne fonctionne pas pour moi, ce que j'ai essayé est:

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. BlogTableViewCell est l'IBOutlet de la cellule et ChainesController est le propriétaire du fichier.

1
groumpf

D'après la documentation UITableView concernant dequeueWithReuseIdentifier: "Une chaîne identifiant l'objet de la cellule à réutiliser. Par défaut, l'identificateur d'une cellule réutilisable est son nom de classe, mais vous pouvez le remplacer par n'importe quelle valeur arbitraire."

Remplacer -reuseIdentifer vous-même est risqué. Que se passe-t-il si vous avez deux sous-classes de votre sous-classe de cellules et les utilisez dans une seule vue sous forme de tableau? S'ils envoient l'appel d'identifiant de réutilisation à super, vous retirerez une cellule du mauvais type .............. Je pense que vous devez remplacer la méthode reuseIdentifier, mais qu'elle renvoie un identifiant supplanté. chaîne. Ou bien, s'il n'en a pas été spécifié, il renvoie la classe sous forme de chaîne.

1
SK9

J'ai suivi les instructions d'Apple liées par Ben Mosher (merci!), Mais j'ai constaté que Apple a omis un point important. L'objet qu'elles conçoivent dans IB est simplement un UITableViewCell, de même que la variable qu'elles chargent. Mais si vous le configurez en tant que sous-classe personnalisée de UITableViewCell et é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 lier à vos éléments personnalisés dans IB. Il faut utiliser des balises de vue pour accéder à ces éléments et créer n'importe quel type de cellule folle que vous voulez.

0
David Casseres

Pour ce que cela vaut, j'ai demandé à un ingénieur iPhone à ce sujet lors d'une des discussions techniques sur l'iPhone. Sa réponse fut: "Oui, il est possible d'utiliser IB pour créer des cellules. Mais non. S'il vous plaît, ne le faites pas."

0
August