2013-06-27 8 views
7

Nella mia app, ho un UITableViewController.Ricarica dati di UITableView sullo sfondo

Il suo TableView è diviso in 3 sezioni.

I dati di download per ciascuna di queste sezioni dal mio server. Per fare ciò, ho 3 funzioni (ad esempio f1 f2 e f3). Ogni aggiornamento di un NSArray corrispondente, utilizzato come origine dati per la mia tabella.

Ora quello che voglio è ricaricare i dati utilizzando queste funzioni e aggiornare il mio tableView una volta che queste 3 funzioni sono state fatte, ma senza disturbare l'utente.

Non sono utilizzato con richiesta asincrona, blocchi, thread ecc ... e sto cercando suggerimenti.

In realtà, qui è quello che faccio:

-(void)viewDidLoad 
{ 
    //some settings 

    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(reloadDatas) userInfo:nil repeats:YES]; 

    dispatch_queue_t queue = dispatch_get_main_queue(); 
    dispatch_async(queue, ^{ 
     [self reloadDatas]; 
    }); 
} 

-(void)reloadDatas 
{ 
    dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 
    dispatch_async(concurrentQueue, ^{ 
     [self f1]; 
     [self f2]; 
     [self f3]; 
     [myDisplayedTable reloadData]; 
    }); 
} 

-(void)f1 
{ 
    //load datas with a url request and update array1 
} 
-(void)f2 
{ 
    //load datas with a url request and update array2 
} 
-(void)f3 
{ 
    //load datas with a url request and update array3 
} 

Ma qui, il mio tableView è "congelato" fino a quando non viene aggiornata.

Non mi interessa l'ordine di esecuzione di f1 f2 e f3, ma devo aspettare che queste 3 funzioni vengano eseguite prima di aggiornare il mio TableView.

Grazie per il vostro aiuto.

EDIT

Grazie per tutte le vostre risposte.

Ecco la soluzione di lavoro:

Come MROS suggets, ho rimosso la coda dispaccio dal viewDidLoad, e sostituire in reloadDatas:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 

con

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

E, infine, Ricarico il mio tavolo in un thread principale

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; }); 

risposta

4

Quindi il "thread di sfondo" è in realtà il thread principale. Devi usare dispatch_get_global_queue e specificare una priorità per ottenere effettivamente un thread diverso. Inoltre, l'invio asincrono in viewDidLoad è inutile poiché tutti i metodi del ciclo di vita del controller di visualizzazione sono chiamati nel thread principale. Raccomanderei di fare qualcosa come segue nei tuoi metodi f1, f2 e f3:

Iniziare lanciando una richiesta di url asincrona, quindi nel blocco di completamento, aggiornare arrayX e ricaricare una sezione specifica del tuo tableview. In questo modo tutte e tre le richieste possono accadere simultaneamente e la tabella aggiorna solo i dati necessari al termine di ciascuna.In alternativa, se si desidera ricaricare solo una volta, basta sostituire la variabile concurrentQueue che si ha con un thread in background e quindi eseguire [tableView reloadData] sul thread principale.

2

In reloadDatas metodo che si deve modificare questa riga:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 

A:

dispatch_queue_t concurrentQueue = dispatch_queue_create("some queue", NULL);

Ma quando si chiama [myDisplayedTable reloadData], è necessario chiamare questa operazione nella coda principale.

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; }); 
+0

Y hai creato ConcurrentQueue? – abhi1992

3

Le risposte precedenti sono assolutamente corrette. Tuttavia la tua implementazione di reloadDatas & viewDidLoad è un po 'problematico.

Giusto per chiarire:

si desidera completare il tempo roba caricamento dei dati in un thread in background, quindi aggiornare l'interfaccia utente/Cellule quando i dati è pronto sul thread principale.

Come così:

-(void)viewDidLoad 
    { 
     dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.backgroundQueue", NULL); 
     dispatch_async(concurrentQueue, ^{ 
      [self reloadDatas]; 
     }); 
    } 

-(void)reloadDatas 
{ 
    // Expensive operations i.e pull data from server and add it to NSArray or NSDictionary 
     [self f1]; 
     [self f2]; 
     [self f3]; 

    // Operation done - now let's update our table cells on the main thread 

    dispatch_queue_t mainThreadQueue = dispatch_get_main_queue(); 
    dispatch_async(mainThreadQueue, ^{ 

     [myDisplayedTable reloadData]; // Update table UI 
    }); 
} 
+0

Ho provato la soluzione, ma le interazioni dell'utente e il ricaricamento si bloccano a vicenda. Voglio dire che reloadDatas non viene chiamato poiché l'utente non ha smesso di scorrere la tabella e l'utente non può scorrere la tabella mentre la tabella non viene aggiornata ... – zbMax

+0

Sei sicuro che non venga chiamato perché l'utente sta scorrendo la tabella ? Prova ad aggiungere alcuni NSlog o punti di interruzione. – smaura777

+0

sì, è ciò che intendo per "interazioni dell'utente": quando si scorre la tabella, il mio NSTimer non chiama la mia funzione fino allo scadere dello scorrimento. – zbMax

1

Un'altra cosa. Estrarre dati da un server e aggiornare le celle di una tabella è piuttosto comune. Non c'è bisogno di code o timer qui. Ecco una struttura alternativa.

dici che stai tirando mp3 dal server: La classe modello è: Music.h/m tuo manager modello è: MusicManager.h/m (Singleton) - conterrà un array di oggetti di musica - che singleton è fondamentalmente la tua origine dati; e, infine, il vostro UITableViewController: MusicTableVC.h/m

In MusicManager.h/m: Hai NSMutableArray che sarà caricato con oggetti Music.h che ho tirare dal server. Puoi farlo non appena l'app viene caricata senza nemmeno aspettare il TableViewController.

All'interno di MusicManager sono disponibili alcuni metodi di supporto per aggiungere o rimuovere elementi dal mutableArray e fornire il conteggio e, naturalmente, i metodi di rete.

Infine: inviare una notifica nel proprio codice di rete. Il tuo UITableViewController dovrebbe ascoltare/osservare quella notifica e "ricaricare" di conseguenza.

[[NSNotificationCenter defaultCenter] postNotificationName:@"NewMusicAdded" object:nil]; 

si richiedono i dati dal server, analizzare i dati in oggetti di musica aggiungerli al vostro array NSMutable e inviare una notifica per lasciare che il tavolo aggiornarsi.

Ricetta piuttosto standard.

Problemi correlati