2011-04-19 6 views
0

Alors voici mon problème. Dans ma page d'accueil de l'application, j'ai un UITableView simple qui peut contenir maximum 3 sections, 2 sections avec un maximum de 3 éléments chacun et la troisième section peut contenir un maximum de 6 éléments.reloadData problème de synchronisation

Chaque section a un en-tête associé à. Le contenu réel provient du web, je fais une demande, le serveur envoie des données, j'analyse la réponse avec NSXMLParser, crée les tableaux pour contenir des données pour chaque section (3 tableaux) et crée également un autre tableau pour garder la référence de les sections que je devrai afficher. Puis, à la fin, j'appelle [myTableView reloadData] pour actualiser le contenu et redessiner la table. Les utilisateurs ont également la possibilité de rafraîchir le contenu eux-mêmes. Pour cela, j'utilise un mécanisme pull-to-refresh comme l'application Facebook.

L'actualisation du contenu à l'aide de la fonction pull-to-refresh finit également par appeler [myTableView reloadData]. Je rencontre un vilain plantage lorsque j'actualise mon contenu et que la table doit changer sa mise en page (par exemple: la table contient actuellement les 3 sections et après je reloadData elle montrera une seule section). J'ai utilisé le débogueur pour localiser le problème. Voici ce que j'ai trouvé:

  1. utilisateur tire vers le bas la table entière pour comme 50 pixels puis libère
  2. Une animation commence qui apporte la table « up » pour tenir compte de la vue 320x50 afficher un message « Chargement » + une UIActivityIndicatorView animée sur le haut de la table
  3. Refresh est déclenché, je fais une nouvelle demande de webservice dans une tâche d'arrière-plan, obtenir de nouvelles données, analyser, tableaux de mise à jour, enfin thread principal effectuer reloadData
  4. en attendant, tout rafraîchissement fait tout ce que j'ai remarqué que UITableView STILL envoie des messages de délégué à:
    • tableView: viewForHeaderInSection:
    • tableView: cellForRowAtIndexPath:

Je figure cela se produit à cause de l'animation à rafraîchissement-pull qui "se déplace" la table et révèle de nouvelles cellules/têtes, appelant ainsi le ci-dessus.

Le problème est que cela provoque un crash horrible parce que les tableaux qui contiennent des données pour les sections et le tableau de sections lui-même sont modifiés simultanément il semble. Dans ce cas, les méthodes déléguées utilisent probablement le tableau d'éléments/sections mis à jour/non encore mis à jour dans le mauvais contexte. C'est, avant

  • numberOfSectionsInTableView:
  • tableView: numberOfRowsInSection:

ont toujours une chance de mettre à jour la nouvelle structure correctement pour les tableaux mis à jour.Je sais que c'est une longue histoire sans aucun échantillon de code, mais j'ai pensé que si je connaissais déjà le problème (du moins j'espère) et si quelqu'un voit mon point, peut-être que quelqu'un peut me diriger dans la bonne direction Corrigez ce problème de synchronisation.

Merci d'avoir lu!

PLUS TARD EDIT:

J'ai trouvé où la question était. Mon mécanisme de traction à l'actualisation utilise un rappel stopLoading qui ressemble à ceci:

- (void)stopLoading 

{ isLoading = NO;

// Hide the header 
[UIView beginAnimations:nil context:NULL]; 
[UIView setAnimationDelegate:self]; 
[UIView setAnimationDuration:0.3]; 
[UIView setAnimationDidStopSelector:@selector(stopLoadingComplete:finished:context:)]; 
self.myTableView.contentInset = UIEdgeInsetsZero; 
[refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1); 
[UIView commitAnimations]; 

}

À un certain moment réinitialiser le contentInset pour ma table fixant à UIEdgeInsetsZero. Ceci et le fait qu'après l'actualisation de l'arrière-plan retournant sur le thread principal, j'appelais stopLoading BEFORE reloadData - déclenché le mauvais rappel des délégués dans le mauvais moment.

Il s'agissait donc d'un problème de synchronisation entre une modification de contentInset et reloadData de ma table.

Répondre

0

Il semble que vous mettez à jour le magasin de données utilisé pour la vue tabulaire à partir de différents threads. Ce n'est pas une bonne idée - les données peuvent facilement entrer dans un état incohérent, et les conteneurs que vous utilisez peuvent ne pas être sûrs pour les threads de toute façon.

La méthode correcte consiste à mettre à jour uniquement ces données à partir du thread principal. Aussi, vous pourriez vouloir regarder les méthodes pour insérer des rangées etc., ce qui rend un rechargement complet rarement nécessaire. Et si vous voulez juste mettre à jour une seule cellule à cause de nouvelles données, alors faites juste rafraîchir cette cellule.

+0

Hmmm, oui. Je pensais à la mise à jour des collections dans un thread différent (c'est la méthode didEndDocument: de NSXMLParser) quand j'écrivais réellement la Question. J'ai donc mis à jour les structures dans ma méthode performSelectorOnMainThread après que l'analyse soit terminée avant reloadData. Toujours le même. reloadData n'a pas de chance de mettre à jour le sourceDelegate parce que d'autres méthodes déléguées sont appelées en utilisant la structure mise à jour mais en fonction de l'ancienne sourceDelegate. – TeodorC