2013-06-27 26 views
7

In meiner App habe ich einen UITableViewController.Daten von UITableView im Hintergrund neu laden

Ihr TableView ist in 3 Abschnitte unterteilt.

Ich lade Daten für jeden dieser Abschnitte von meinem Server. Um dies zu tun, habe ich 3 Funktionen (zum Beispiel f1 f2 und f3). Jeder aktualisiert ein entsprechendes NSArray, das als Datenquelle für meine Tabelle verwendet wird.

Nun, was ich will, ist Daten mit diesen Funktionen neu zu laden und aktualisieren Sie meine TabelleView, sobald diese 3 Funktionen erledigt sind, aber ohne den Benutzer zu stören.

Ich bin nicht mit asynchronen Anfrage verwendet, Blöcke, Threads etc ... und ich bin auf der Suche nach Tipps.

Eigentlich ist hier, was ich tue:

-(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 
} 

Aber hier mein Tableview „eingefroren“, bis sie aktualisiert wird.

Ich interessiere mich nicht für die Reihenfolge der Ausführung von f1 f2 und f3, aber ich muss warten, bis diese 3 Funktionen durchgeführt werden, bevor ich meine TableView aktualisieren.

Danke für Ihre Hilfe.

EDIT

Vielen Dank für Ihre Antworten.

Hier ist die Arbeitslösung:

Als MROS suggets ich die Absende-Warteschlange aus der viewDidLoad entfernt und ersetzt in reloadDatas:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 

mit

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

Und schließlich, Ich lade meinen Tisch in einen Hauptfaden

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

Antwort

4

So ist Ihr "Hintergrund Thread" eigentlich Ihr Hauptthema. Sie müssen dispatch_get_global_queue verwenden und eine Priorität angeben, um tatsächlich einen anderen Thread zu erhalten. Außerdem ist das Dispatch-Async in viewDidLoad nutzlos, da alle View-Controller-Lifecycle-Methoden im Haupt-Thread aufgerufen werden. Ich würde empfehlen, etwas wie folgt in Ihren f1, f2 und f3 Methoden zu tun:

Beginnen Sie mit dem Starten einer asynchronen URL-Anfrage, dann im Abschlussblock, aktualisieren Sie ArrayX und laden Sie einen bestimmten Abschnitt Ihrer Tabellenansicht neu. Auf diese Weise können alle drei Anfragen gleichzeitig ausgeführt werden, und die Tabelle aktualisiert nur die erforderlichen Daten, wenn jede abgeschlossen ist.Wenn Sie nur einmal neu laden möchten, ersetzen Sie einfach die Variable concurrentQueue, die Sie haben, mit einem Hintergrundthread und führen Sie dann [tableView reloadData] im Hauptthread aus.

2

In reloadDatas Methode sollten Sie diese Zeile:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 

An:

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

Aber wenn man [myDisplayedTable reloadData] nennen, müssen Sie in der Hauptwarteschlange diesen Vorgang nennen.

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

Y haben Sie concurrentQueue erstellt? – abhi1992

3

Die vorherigen Antworten sind absolut richtig. Allerdings ist Ihre Implementierung von reloadDatas & viewDidLoad ein bisschen problematisch.

Nur um zu klären:

Sie möchten die zeitaufwändige Datenlade Sachen in einem Hintergrund-Thread vervollständigen, dann die UI/Zellen aktualisieren, wenn Ihre Daten auf dem Haupt-Thread bereit ist.

Wie so:

-(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

Ich habe Ihre Lösung versucht, aber Benutzerinteraktionen und Neuladevorgänge blockieren sich gegenseitig. Ich meine reloadDatas wird nicht aufgerufen, da der Benutzer das Scrollen der Tabelle nicht beendet hat und der Benutzer die Tabelle nicht scrollen kann, während die Tabelle nicht aktualisiert wird ... – zbMax

+0

Sind Sie sicher, dass sie nicht aufgerufen wird, weil der Benutzer die Tabelle scrollt ? Versuchen Sie, ein paar NSLogs oder Haltepunkte hinzuzufügen. – smaura777

+0

Ja, das ist, was ich unter 'Benutzerinteraktionen' verstehe: Beim Scrollen der Tabelle ruft mein NSTimer meine Funktion erst auf, wenn der Bildlauf beendet ist. – zbMax

1

Eine andere Sache. Das Ziehen von Daten von einem Server und das Aktualisieren von Tabellenzellen ist ziemlich üblich. Keine Warteschlangen oder Timer erforderlich. Hier ist eine alternative Struktur.

Sagen Sie MP3-Dateien von Ihrem Server sind ziehen: Ihre Modellklasse ist: Music.h/m Ihr Modell-Manager ist: MusicManager.h/m (Singleton) - es wird eine Reihe von Musik-Objekte enthalten - das Singleton ist im Grunde Ihre Datenquelle; und schließlich Ihre UITableViewController: MusicTableVC.h/m

In MusicManager.h/m: Sie haben ein NSMutableArray, die mit Music.h Objekte geladen werden, die Sie ziehen vom Server haben. Sie können das tun, sobald Sie die App laden, ohne auf den TableViewController zu warten.

In MusicManager haben Sie ein paar Hilfsmethoden zum Hinzufügen oder Entfernen von Elementen aus dem mutableArray und bieten die Anzahl und natürlich Ihre Netzwerkmethoden.

Endlich: Veröffentlichen Sie eine Benachrichtigung in Ihrem Netzwerkcode. Ihr UITableViewController sollte diese Benachrichtigung abhören/beobachten und entsprechend neu laden.

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

Sie abfragen Daten von Ihrem Server, analysieren die Daten in Musik Objekte in Ihre NSMutable Array und senden Sie uns eine Mitteilung der Tabelle lassen selbst aktualisieren.

Ziemlich Standardrezept.

Verwandte Themen