Implementierung einer Methode, die einen Block als Rückruf verwendet

70

Ich möchte eine ähnliche Methode schreiben:

+(void)myMethodWithView:(UIView *)exampleView completion:(void (^)(BOOL finished))completion;

Ich habe im Grunde die Syntax einer der Klassenmethoden von Apple reduziert für UIView:

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;

Und würde erwarten, dass es so verwendet wird:

[myFoo myMethodWithView:self.view completion:^(BOOL finished){
                     NSLog(@"call back success");
                 }];

Meine Frage ist, wie kann ich das umsetzen? Wenn mich jemand auf die richtige Dokumentation verweisen kann, wäre das großartig, und ein sehr einfaches Beispiel wäre sehr willkommen (oder eine ähnliche Antwort auf Stack Overflow - ich konnte keine finden). Ich weiß immer noch nicht genug über Delegierte, um festzustellen, ob dies überhaupt der richtige Ansatz ist!

Ich habe ein grobes Beispiel dafür, was ich erwartet hätte, in die Implementierungsdatei aufgenommen, aber da ich keine Informationen finden kann, ist es eine Vermutung.

+ (void)myMethod:(UIView *)exampleView completion:(void (^)(BOOL finished))completion {
    // do stuff

    if (completion) {
        // what sort of syntax goes here? If I've constructed this correctly!
    }

}
Chris
quelle
Ich frage mich, warum niemand die Tatsache erwähnt hat, dass der finishedin dem Parametertyp in diesem Beispiel ziemlich unnötig ist ...
Funktion7

Antworten:

84

Sie können einen Block wie eine reguläre Funktion aufrufen:

BOOL finished = ...;
if (completion) {
    completion(finished);
}

Das bedeutet, dass die Implementierung einer vollständigen Blockfunktion anhand Ihres Beispiels folgendermaßen aussehen würde:

+ (void)myMethod:(UIView *)exampleView completion:(void (^)(BOOL finished))completion {
    if (completion) {
        completion(finished);
    }
}
omz
quelle
Das war schmerzlich einfach, vielen Dank! Site sagt, es ist zu früh, um die Antwort zu akzeptieren. Ich werde es tun, sobald ich wieder am Computer bin
Chris
Beachten Sie auch, dass Sie in Ihrem Beispiel einen Block auf einem Stapel erstellen, sodass die Möglichkeit besteht, dass der Block stirbt, bevor er ausgeführt wird. Um dies zu vermeiden, erstellen Sie in Ihrer Methode [[Abschlusskopie] Autorelease], die den Block akzeptiert.
Timur Kuchkarov
@ TimurKuchkarov - Können Sie einen Code einfügen, damit ich sehen kann, wohin die [Abschlusskopie] in der Methode gehen soll? Alles ein wenig verwirrend für meinen einfachen Verstand :)
So Over It
1
"Normalerweise sollten Sie einen Block nicht kopieren (oder beibehalten) müssen. Sie müssen nur dann eine Kopie erstellen, wenn Sie erwarten, dass der Block nach Zerstörung des Bereichs verwendet wird, in dem er deklariert wurde. Durch das Kopieren wird ein Block auf den Heap verschoben . ". Ein guter Link ist auch - mikeash.com/pyblog/… . Ich kopiere normalerweise zu Beginn der Methode, bei der der Block übergeben wird.
Timur Kuchkarov
1
@ErhanDemirci das completionist der eigentliche Block. Es ist in der Methodensignatur definiert. (void (^) (BOOL beendet)) Vervollständigung ermöglicht das Aufrufen einer Vervollständigungs () -Methode, die als Rückruf verwendet wird. Schauen Sie sich die Dokumente zu Äpfeln an: developer.apple.com/library/ios/documentation/cocoa/conceptual/…
Johnathon Sullinger
5

Ich würde Ihnen wärmstens empfehlen, sich über Blöcke zu informieren, um zu verstehen, was passiert.

Chaitanya Gupta
quelle
wenn ich kopiere + (void) myMethod: (UIView *) exampleView-Vervollständigung: (void (^) (BOOL beendet)) Vervollständigung {if (Vervollständigung) {Vervollständigung (beendet); }} Ich bekomme "Verwendung der nicht deklarierten Kennung beendet" ....
alex440