2010-10-31 7 views
0

J'ai une classe DetailsViewController et une classe ItemsViewController. (Tous deux dérivés de UITableViewController)Quel est le bon moment pour reloadData

La sélection de l'un des éléments dans ItemsViewController fait apparaître DetailsViewController. Pour l'obtenir pour afficher les nouvelles données sur tout, mais le premier, j'ai actuellement

 
- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    [[self navigationItem] setTitle:title]; 
    [[self tableView] reloadData]; 
} 

Ce fonctionne, mais il se sent comme tuer une mouche avec un marteau de forgeron. Qu'est-ce qu'un meilleur façon de faire cela?

Merci à l'avance,

Alan

+0

quel est ce segment de code ci-dessus de? Le ItemsView ou le DetailsView ... vous avez dit qu'ils étaient les deux tables. –

+0

désolé, j'aurais dû mentionner. Cela vient de DetailsView. – Alan

Répondre

1

Combinant idées de plusieurs commentaires ici:

Ajout

BOOL needReload
en tant que membre variable au contrôleur de détails.

Ensuite, dans le contrôleur de détails:

 
- (void)setData:(DataClass *)value { 
    if (value == data) 
     return; 
    id pointer = data; 
    data = [value retain]; 
    [pointer release];  // release after retain 
    needReload = TRUE; 
} 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    if(needReload){ 
     [[self navigationItem] setTitle:title]; 
     [[self tableView] reloadData]; 
     needReload = FALSE; 
    } 
} 
0

Si vous savez que seules les lignes ou sections spécifiques vont changer, vous pouvez diriger la vue de cuisson pour recharger uniquement les lignes ou sections. Autre que cela, -reloadData est le chemin à parcourir pour la plupart des vues de table.

0

Je suppose que les éléments de la table de détails changent en fonction de l'élément sélectionné dans la table des éléments. Alors, ouais, ça devrait aller. À part cela, vous pouvez vérifier si le même élément est sélectionné la dernière fois et ne pas appeler reloadData dans ce cas.

0

Alan,

Votre déclaration de « Pour l'obtenir pour afficher les nouvelles données sur tout, mais le premier » me concerne - car il me dit que vous avez probablement une seule instance DetailsViewController.

Dans votre première vue de table, ItemsViewController, vous avez probablement une méthode didSelectRowAtIndexPath: que vous utilisez pour pousser le DetailsViewController sur la pile UINavigationController. Comment résoudre ce problème est simplement de créer/détruire un nouveau DetailsViewController chaque fois que mon utilisateur tape entre les vues. Alors, mon didSelectRowAtIndexPath: ressemble souvent:

- (void) didSelectRowAtIndexPath:(NSIndexPath*)indexPath 
{ 
    NSInteger selectedRow = indexPath.row; 

    // Create a new view controller 
    DetailsViewController *tmpVC = [[DetailsViewController alloc] initWithNibName:@"foo" bundle:nil]; 

    // Tell our new view controller what data it should be using 
    tmpVC.tableData = [self.someArrayOfData objectAtIndex:selectedRow]; 

    // Push view controller and release it 
    [self.navigationController pushViewController:tmpVC animated:YES]; 
    [tmpVC release]; 
} 

Cet exemple suppose que vous avez toutes les données nécessaires pour les deux contrôleurs de vue dans votre ItemsViewController - qui peuvent ne pas être le cas ..?

Quoi qu'il en soit, votre DetailsViewController charge automatiquement les données. Lorsque vous appuyez sur "Retour" pour revenir à ItemsViewController, UINavigationController le lâche, le détruisant. Ensuite, lorsque l'utilisateur appuie sur une cellule différente, nous réexécutons ce code, créant ainsi un tout nouveau contrôleur avec des données flambant neuves - donc, bien sûr, lorsqu'il est affiché, il charge automatiquement les données - il n'est jamais affiché auparavant.

Ce que vous pouvez faire dans votre code est de conserver le DetailsViewController en tant que propriété de la classe ItemsViewController, puis de réutiliser l'objet. Cela peut aussi fonctionner si vous êtes préoccupé par les allocations (par exemple, si c'est une allocation très "lourde" pour faire un DetailsViewController), mais alors je pense que le meilleur endroit pour appeler reloadData n'est pas dans la classe elle-même. plutôt de la méthode didSelectRowAtIndexPath: de ItemsViewController. La raison pour laquelle je promeus l'approche de création/destruction par opposition à l'approche du "pattern de poids mouche" est qu'elle maintient votre code plus séparé - moins il y a de liens entre les contrôleurs de vue, mieux c'est.Bien sûr, ItemsViewController dépendra toujours de DetailsViewController et le connaîtra, mais il ne doit pas nécessairement être l'inverse - et si vous ajoutez l'appel reloadData à viewWillAppear:animated:, vous ajoutez implicitement une dépendance non-code entre les deux. . Vous savez que lorsque ItemsViewController est le "parent" dans la pile de navigation, c'est le bon comportement - mais que se passe-t-il si vous avez soudainement commencé à réutiliser cette vue dans une autre partie de votre application qui ne nécessite pas de rechargement? C'est un coup de performance pour un, et de plus, c'est le genre de dépendance cachée qui peut finir dans un bug méchant-à-trace un jour. Donc, je garderais les détails stupides et je ferais en sorte que les objets contiennent toute la complexité, s'il est vraiment nécessaire de n'avoir qu'un seul DetailsViewController (contrairement à ma première idée de le recréer à chaque fois).

+0

votre hypothèse de ce que je fais est exactement correcte. Je dois réfléchir davantage au coût relatif de l'allocation et de la désallocation de la vue détaillée. Hmmm .. – Alan

+0

Quelle est la taille de votre tableau de données? Combien de lignes généralement dans les articles? Combien de données dans Détails? – makdad

0

Je proposerais que reloadData et setTitle soient dans viewDidLoad et dans le setter - je suppose que vous définissez une propriété dans DetailsViewController qui change la source de données de la table. Donc viewDidLoad recharge et définit le titre, si la propriété a été définie, le setter recharge et définit le titre si isViewLoaded et la nouvelle valeur est différente de l'ancienne.

- (void)setSmth:(SmthClass *)value { 
    if (value == smth) // if they are the same and SmthClass is immutable, 
         // otherwise use isEqual and [self.tableView reloadData] 
         // before returning... 
     return; 
    id pointer = smth; // if it's a retain property 
    smth = [value retain]; 
    [pointer release];  // release after retain just to be extra safe 

    if ([self isViewLoaded]) { 
      [self.tableView reloadData]; 
      [self setTitle:title]; 
    } 
} 

- (void)viewDidLoad { 
    if (smth) { 
     [self.tableView reloadData]; // maybe redundant... 
     [self setTitle:title]; 
    } 
} 

Ou vous pouvez utiliser (protocole NSKeyValueObserving) valeur-clé d'observation pour observer votre propriété et reloadData la notification ...

+0

Cela ne réduit pas le nombre de fois que reloadData sera appelé et ajoute un surcoût supplémentaire. Mais je pense que cela devient une partie de la solution (en particulier combiné avec Altealice ci-dessous) – Alan

+0

En outre, viewDidLoad n'est pas appelé chaque fois que le contrôleur est affiché. – Alan

Questions connexes