2013-02-13 7 views

risposta

34

È necessario considerare il blocco di completamento come una variabile. Il metodo accetta un blocco come parte dei suoi parametri, quindi lo memorizza per dopo.

- (void)myMethodWithCompletionHandler:(void (^)(id, NSError*))handler;

È possibile typedef che tipo di blocco per una più facile lettura:

typedef void (^CompletionBlock)(id, NSError*);

e quindi memorizzare il tuo blocco come una variabile di istanza:

Nel vostro @interface: CompletionBlock _block;

Nel mio metodo .. _block = [handler copy]

Poi, quando si desidera che il blocco di completamento da eseguire appena lo chiamano come un blocco normale:

_block(myData, error);

+2

Assicurarsi di utilizzare '_block = [copia handler];' '... – bbum

+1

copy' è necessario in modo che il blocco viene copiato nell'heap (quello predefinito dal client che richiama il tuo codice viene archiviato nello stack per impostazione predefinita). – yonel

34

Se fosse stato per un metodo asincrono Si potrebbe fare in questo modo

- (void)asynchronousTaskWithCompletion:(void (^)(void))completion; 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    // Some long running task you want on another thread 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     if (completion) { 
     completion(); 
     } 
    }); 
    }); 
} 

invocato con

[self asynchronousTaskWithCompletion:^{ 
    NSLog(@"It finished"); 
}]; 

Qualcosa da non E è la guardia per assicurarsi che completion stia puntando a qualcosa altrimenti andremo in crash se proviamo ad eseguirlo.

Un altro modo in cui utilizzo spesso i blocchi per i gestori di completamento è quando un viewController è terminato e desidera essere estratto da uno stack di navigazione.

@interface MyViewController : UIViewController 

@property (nonatomic, copy) void (^onCompletion)(void); 

@end 

@implementation MyViewController 

- (IBAction)doneTapped; 
{ 
    if (self.onCompletion) { 
    self.onCompletion(); 
    } 
} 

@end 

si dovrebbe impostare il blocco di completamento quando si spinge questo punto di vista nello stack

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender; 
{ 
    MyViewController *myViewController = segue.destinationViewController; 
    myViewController.onCompletion = ^{ 
    [self.navigationController popViewControllerAnimated:YES]; 
    }; 
} 
+0

non risponderebbe alla seconda chiamata di chiamata asincrona prima del completamento dell'attività a esecuzione prolungata? – marciokoko

+0

Come sarebbe? Se il codice long non è stato completato, non avrai raggiunto il prossimo 'dispatch_async' –

+0

Sì perché è in un altro thread, non è vero? – marciokoko

0

risposta di Chris C è corretta (ed è stato molto utile per me) con un avvertimento:

Posizionamento del declaration CompletionBlock _block; in @interface non è thread-safe.

Inserire CompletionBlock _block = [handler copy]; in myMethod… invece se è possibile che myMethod… venga chiamato da più thread (o code di invio).

Grazie @ Chris C.

4

Ecco un esempio di un metodo che accetta una stringa e un gestore di completamento come variabili. Il gestore di completamento può anche ricevere una stringa.

Swift 2.2 Sintassi

Defintion:

func doSomething(input: String, completion: (result: String) -> Void { 
    print(input) 
    completion(result: "we are done!") 
} 

Chiamando la funzione:

doSomething("cool put string!") { (result) in 
     print(result) 
} 
Problemi correlati