109 votes

Être averti lorsque UITableView a fini de demander des données?

Est-il un moyen de savoir si un UITableView a fini de poser pour des données à partir de sa source de données?

Aucun des viewDidLoad/viewWillAppear/viewDidAppear méthodes de l'associé-vue-contrôleur (UITableViewController) sont d'utilisation ici, car ils ont tous le feu trop tôt. Aucun d'entre eux (entièrement à juste titre) la garantie que les requêtes à la source de données ont fini pour le moment (par exemple, jusqu'à ce que l'affichage défile à l'écran).

Une solution de contournement que j'ai trouvé est d'appeler reloadData en viewDidAppear, depuis, lors de l' reloadData rendements, la vue de la table est la garantie d'avoir fini d'interroger la source de données comme beaucoup comme il se doit pour le moment.

Toutefois, cela semble plutôt méchant, comme je suppose qu'il est à l'origine de la source de données afin de fournir les mêmes informations deux fois (une fois automatiquement, et une fois à cause de l' reloadData appel) lorsqu'il est chargé pour la première fois.

La raison pour laquelle je veux faire ce que je veux préserver la position de défilement de l' UITableView - mais jusqu'au niveau du pixel, pas seulement la plus proche de la ligne.

Lors de la restauration de la position de défilement (à l'aide d' scrollRectToVisible:animated:), j'ai besoin de la vue de la table de déjà disposer de suffisamment de données, ou bien l' scrollRectToVisible:animated: appel de la méthode ne fait rien (c'est ce qui arrive si vous placez l'appel sur son propre dans l'une quelconque des viewDidLoad, viewWillAppear ou viewDidAppear).

Merci d'avance pour votre aide!

61voto

Eric MORAND Points 2979

Cette réponse ne semble pas être fonctionne plus, en raison de certaines modifications apportées à UITableView mise en œuvre puisque la réponse a été écrit. Voir ce commentaire : recevez des notifications lorsque UITableView a fini de poser pour les données?

J'ai joué avec ce problème pour un couple de jours et de penser que sous-classement UITableView de reloadData est la meilleure approche :

- (void)reloadData {

    NSLog(@"BEGIN reloadData");

    [super reloadData];

    NSLog(@"END reloadData");

}

reloadData n'est pas la fin avant de la table a fini de recharger ses données. Ainsi, lors de la deuxième NSLog est déclenché, le tableau a réellement finir en demandant des données.

J'ai sous-classé UITableView pour envoyer des méthodes pour le délégué avant et après reloadData. Il fonctionne comme un charme.

53voto

iPrabu Points 7216

J'ai en effet un même scénario dans mon application et de la pensée de publier ma réponse à vous les gars

Après avoir essayé la plupart des réponses suggérées ici, enfin c'est la seule chose qui a fonctionné pour moi.

[yourTableview reloadData];

dispatch_async(dispatch_get_main_queue(),^{
        NSIndexPath *path = [NSIndexPath indexPathForRow:yourRow inSection:yourSection];
        //Basically maintain your logic to get the indexpath
        [yourTableview scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
 });

Alors, comment cela fonctionne.

Fondamentalement, lorsque vous effectuez une recharge, le thread principal est occupé donc, à l'époque, lorsque nous faisons un envoi asynchrone fil, le bloc va attendre que le thread principal est parachevé. Donc, une fois que la tableview a été complètement chargé, le thread principal sera obtient terminer et il enverra notre méthode de bloc

Testé dans iOS7 fonctionne super;)

25voto

bandejapaisa Points 8425

EDIT: la réponse est en fait pas une solution. Il apparaît probablement fonctionner dans un premier temps parce que le rechargement peut se produire assez rapidement, mais en fait la fin du bloc ne sont pas nécessairement appelés après que les données ont complètement fini de rechargement - parce que reloadData ne bloque pas. Vous devriez probablement chercher une meilleure solution.

Pour développer sur @Eric MORAND réponse, permet de mettre fin à bloc. Qui n'aime pas un bloc?

@interface DUTableView : UITableView

   - (void) reloadDataWithCompletion:( void (^) (void) )completionBlock;

@end

et...

#import "DUTableView.h"

@implementation DUTableView

- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock {
    [super reloadData];
    if(completionBlock) {
        completionBlock();
    }
}

@end

Utilisation:

[self.tableView reloadDataWithCompletion:^{
                                            //do your stuff here
                                        }];

11voto

Mark Kryzhanouski Points 4165

C'est ma solution. Fonctionne à 100% et utilisé dans de nombreux projets. C'est simple UITableView sous-classe.

@protocol MyTableViewDelegate<NSObject, UITableViewDelegate>
@optional
- (void)tableViewWillReloadData:(UITableView *)tableView;
- (void)tableViewDidReloadData:(UITableView *)tableView;
@end

@interface MyTableView : UITableView {
    struct {
        unsigned int delegateWillReloadData:1;
        unsigned int delegateDidReloadData:1;
        unsigned int reloading:1;
    } _flags;
}
@end

@implementation MyTableView
- (id<MyTableViewDelegate>)delegate {
    return (id<MyTableViewDelegate>)[super delegate];
}

- (void)setDelegate:(id<MyTableViewDelegate>)delegate {
    [super setDelegate:delegate];
    _flags.delegateWillReloadData = [delegate respondsToSelector:@selector(tableViewWillReloadData:)];
    _flags.delegateDidReloadData = [delegate    respondsToSelector:@selector(tableViewDidReloadData:)];
}

- (void)reloadData {
    [super reloadData];
    if (_flags.reloading == NO) {
        _flags.reloading = YES;
        if (_flags.delegateWillReloadData) {
            [(id<MyTableViewDelegate>)self.delegate tableViewWillReloadData:self];
        }
        [self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];
    }
}

- (void)finishReload {
    _flags.reloading = NO;
    if (_flags.delegateDidReloadData) {
        [(id<MyTableViewDelegate>)self.delegate tableViewDidReloadData:self];
    }
}

@end

Il est similaire à @Josh Brown solution à une exception près. Aucun délai nécessaire dans performSelector méthode. Peu importe combien de temps reloadData prend. tableViewDidLoadData: toujours se déclenche lorsque tableView termine en demandant à la source de données cellForRowAtIndexPath.

Même si vous ne voulez pas à la sous-classe UITableView vous pouvez simple appel performSelector:@selector(finishReload) withObject:néant afterDelay:0.0 f et du sélecteur appelée juste après rechargement terminé. Mais vous devez vous assurer que le sélecteur de sont appelé qu'une seule fois par un reloadData:

[self.tableView reloadData];
[self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];

Profitez de. :)

11voto

Black Coder Points 167

reloadData demande simplement des données pour les cellules visibles. Dit, pour être averti lorsque la partie spécifique de votre table est chargée, veuillez lier la méthode tableView: willDisplayCell: .

 - (void) reloadDisplayData
{
    isLoading =  YES;
    NSLog(@"Reload display with last index %d", lastIndex);
    [_tableView reloadData];
    if(lastIndex <= 0){
    isLoading = YES;
    //Notify completed
}

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row >= lastIndex){
    isLoading = NO;
    //Notify completed
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X