6 Stimmen

Vergleich GCD vs. performSelectorInBackground: dispatch_async nicht im Hintergrund

Grand Central Dispatch ist großartig und reduziert die Menge an Code, aber warum kann ich nicht etwas in einem Hintergrund-Thread laufen lassen?
Ich habe eine Beispielanwendung erstellt, um zu zeigen, was ich meine (keine der kommentierten Funktionen):

- (IBAction)performSel {
    [self performSelectorInBackground:@selector(doStuff) withObject:nil];
    [NSThread sleepForTimeInterval:3];
    [[self.view.subviews lastObject] removeFromSuperview];
}

- (IBAction)gcd {
    dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
    //dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    //dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    //dispatch_async(dispatch_get_main_queue(), ^(void) {
    //dispatch_sync(dispatch_get_main_queue(), ^(void) {
        [self doStuff]; // only for readability, will move the code on success
    });
    [NSThread sleepForTimeInterval:3];
    [[self.view.subviews lastObject] removeFromSuperview];
}

- (void)doStuff {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

    UIView *abortingView = [[UIView alloc]initWithFrame: self.view.bounds];
    abortingView.backgroundColor = [UIColor whiteColor];
    abortingView.alpha = 0.7;
    [self.view insertSubview:abortingView atIndex:10];
    [abortingView release];

    [pool drain];
}

die [NSThread sleepForTimeInterval:3]; ist es, eine Standard-UI-Funktionalität zu simulieren. Zum Beispiel, wenn jemand von einer Navigationsansicht zu einer anderen wechselt.
Kopieren Sie den Code einfach in eine neue ansichtsbasierte Anwendung, erstellen Sie zwei Schaltflächen und verbinden Sie sie.

24voto

Kazuki Sakamoto Punkte 13924

UIKit-Klassen sollten nur vom Hauptthread einer Anwendung aus verwendet werden. (Ab iOS4 ist das Zeichnen in einen Grafikkontext thread-sicher.) Sie können keine UIKit-Sachen in einem Hintergrund-Thread verwenden.

Daher können Sie in dieser Situation nur dispatch_async(dispatch_get_main_queue(), block) verwenden.

dispatch_async(dispatch_get_main_queue(), ^(void) {

Er ruft den Block auf dem Hauptthread in der Runloop des Hauptthreads auf.

dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

Er ruft den Block in einem Hintergrund-Thread auf. Sie können ihn nicht verwenden, weil Sie UIKit in dem Block verwenden möchten. Und seien Sie vorsichtig dispatch_async(dispatch_queue_create( Wenn Sie die serielle Warteschlange, die durch dispatch_queue_create erstellt wurde, freigeben, kann dies zu einem Speicherverlust führen.

dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

dispatch_sync wartet, bis der Block fertig ist.

dispatch_sync(dispatch_get_main_queue(), ^(void) {

Es verursacht DEADLOCK.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X