2011-01-10 15 views
0

Ich muss eine komplexe (dh lange) Aufgabe ausführen, nachdem der Benutzer auf eine Schaltfläche klickt. Der Knopf öffnet ein Blatt und der lang andauernde Vorgang wird mit dispatch_async und anderen Grand Central Dispatch Stuff gestartet.Blätter und lange laufende Aufgaben

Ich habe den Code geschrieben und es funktioniert gut, aber ich brauche Hilfe zu verstehen, wenn ich alles richtig gemacht habe oder wenn ich (aufgrund meiner Ignoranz) ein mögliches Problem ignoriert habe.

der Benutzer die Schaltfläche klickt und das Blatt geöffnet wird, enthält der Block die Aufgabe lange (in diesem Beispiel läuft es nur für (;;) -Schleife Der Block enthält auch die Logik, um das Blatt zu schließen, wenn Aufgabe abschließt.

-(IBAction)openPanel:(id)sender { 
    [NSApp beginSheet:panel 
     modalForWindow:[self window] 
     modalDelegate:nil 
     didEndSelector:NULL 
      contextInfo:nil]; 

    void (^progressBlock)(void); 
    progressBlock = ^{ 

     running = YES; // this is a instance variable 

     for (int i = 0; running && i < 1000000; i++) { 
      [label setStringValue:[NSString stringWithFormat:@"Step %d", i]]; 
      [label setNeedsDisplay: YES]; 
     } 
     running = NO; 
     [NSApp endSheet:panel]; 
     [panel orderOut:sender]; 

    }; 

    //Finally, run the block on a different thread. 
    dispatch_queue_t queue = dispatch_get_global_queue(0,0); 
    dispatch_async(queue,progressBlock); 
} 

die Platte enthält eine Stopp-Taste, die Benutzer die Aufgabe vor seiner Fertigstellung

-(IBAction)closePanel:(id)sender { 
    running = NO; 
    [NSApp endSheet:panel]; 
    [panel orderOut:sender]; 
} 

Antwort

2

Dieser Code ein potenzielles Problem muss aufhören können, wo es Wert des Statustext legt. Grundsätzlich werden alle Objekte in AppKit sind nur darf man f nennen aus dem Hauptthread und kann auf seltsame Weise brechen, wenn sie nicht sind. Sie rufen die Methoden setStringValue: und setNeedsDisplay: auf dem Etikett aus dem Thread auf, auf dem die globale Warteschlange ausgeführt wird. Um dies zu beheben, sollten Sie die Schleife wie so schreiben:

for (int i = 0; running && i < 1000000; i++) { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [label setStringValue:[NSString stringWithFormat:@"Step %d", i]]; 
     [label setNeedsDisplay: YES]; 
    }); 
} 

Dadurch wird der Beschriftungstext aus dem Haupt-Thread gesetzt, wie AppKit erwartet.

Verwandte Themen