126 Stimmen

Wie man Rückrufe in Objective-C ausführt

Wie führt man Callback-Funktionen in Objective-C aus?

Ich möchte nur ein paar fertige Beispiele sehen, dann sollte ich es verstehen.

145voto

Jens Ayton Punkte 14459

Der Vollständigkeit halber, da StackOverflow RSS gerade zufällig die Frage für mich wiederbelebt hat, ist die andere (neuere) Option, Blöcke zu verwenden:

@interface MyClass: NSObject
{
    void (^_completionHandler)(int someParameter);
}

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end

@implementation MyClass

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler
{
    // NOTE: copying is very important if you'll call the callback asynchronously,
    // even with garbage collection!
    _completionHandler = [handler copy];

    // Do stuff, possibly asynchronously...
    int result = 5 + 3;

    // Call completion handler.
    _completionHandler(result);

    // Clean up.
    [_completionHandler release];
    _completionHandler = nil;
}

@end

...

MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result){
    // Prints 10
    NSLog(@"%i", x + result);
}];

2 Stimmen

@Ahruman: Was bedeutet das "^"-Zeichen in "void (^_completionHandler)(int someParameter);"? Könnten Sie erklären, was diese Zeile bewirkt?

2 Stimmen

Können Sie erklären, warum Sie den Callback-Handler kopieren müssen?

97voto

Jon Hess Punkte 14197

Normalerweise werden Rückrufe in Objective C mit Delegaten durchgeführt. Hier ist ein Beispiel für eine benutzerdefinierte Delegaten-Implementierung;


Header-Datei:

@interface MyClass : NSObject {
    id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end

@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end

Implementierung (.m) Datei

@implementation MyClass
- (void)setDelegate:(id)aDelegate {
    delegate = aDelegate; /// Not retained
}

- (void)doSomething {
    [delegate myClassWillDoSomething:self];
    /* DO SOMETHING */
    [delegate myClassDidDoSomething:self];
}
@end

Dies veranschaulicht den allgemeinen Ansatz. Sie erstellen eine Kategorie auf NSObject, die die Namen Ihrer Callback-Methoden deklariert. NSObject implementiert diese Methoden nicht wirklich. Diese Art von Kategorie wird als informelles Protokoll bezeichnet. Sie sagen nur, dass viele Objekte diese Methoden implementieren könnten. Sie sind eine Möglichkeit, die Typsignatur des Selektors weiterzugeben.

Als Nächstes wird ein Objekt zum Delegaten von "MyClass", und MyClass ruft die Delegatenmethoden des Delegaten nach Bedarf auf. Wenn Ihre Delegaten-Callbacks optional sind, werden Sie typischerweise auf der Dispatch-Seite mit etwas wie "if ([delegate respondsToSelector:@selector(myClassWillDoSomething:)) {". In meinem Beispiel ist der Delegat verpflichtet, beide Methoden zu implementieren.

Anstelle eines informellen Protokolls können Sie auch ein formales Protokoll verwenden, das mit @protocol definiert ist. Wenn Sie das tun, ändern Sie den Typ des Delegatensetzers und der Instanzvariablen in " id <MyClassDelegate> " anstelle von nur " id ".

Außerdem werden Sie feststellen, dass der Delegierte nicht beibehalten wird. Dies geschieht in der Regel, weil das Objekt, das Instanzen von "MyClass" "besitzt", normalerweise auch der Delegat ist. Wenn MyClass seinen Delegaten beibehalten würde, dann gäbe es einen Retain-Zyklus. Es ist eine gute Idee, in der dealloc-Methode einer Klasse, die eine MyClass-Instanz hat und ihr Delegat ist, die Delegate-Referenz zu löschen, da sie ein schwacher Rückverweis ist. Andernfalls, wenn etwas die MyClass-Instanz am Leben hält, haben Sie einen baumelnden Zeiger.

1 Stimmen

+1 Gute und ausführliche Antwort. Das i-Tüpfelchen wäre ein Link zu einer ausführlicheren Apple-Dokumentation über Delegierte :-)

0 Stimmen

Jon, vielen Dank für deine Hilfe. Ich weiß Ihre Hilfe wirklich zu schätzen. Es tut mir leid, aber ich bin mir über die Antwort nicht ganz im Klaren. Message .m ist eine Klasse, die sich während des Aufrufs der doSomething-Funktion selbst als Delegierten setzt. Ist doSomething die Callback-Funktion, die der Benutzer aufruft? da ich den Eindruck habe, dass der Benutzer doSomething aufruft, und Ihre Callback-Funktionen myClassWillDoSomethingg & myClassDidDoSomething sind. Können Sie mir auch zeigen, wie ich eine höhere Klasse erstellen kann, die die Rückruffunktion aufruft. Ich bin ein C-Programmierer und daher mit der Obj-C-Umgebung noch nicht so vertraut.

0 Stimmen

"Message .m" bedeutete nur, in Ihrer .m-Datei. Sie hätten eine separate Klasse, nennen wir sie "Foo". Foo hätte eine Variable "MyClass *myClass", und irgendwann würde Foo sagen "[myClass setDelegate:self]". Wenn danach irgendjemand, einschließlich foo, die doSomethingMethode auf dieser Instanz von MyClass aufruft, würden bei foo die Methoden myClassWillDoSomething und myClassDidDoSomething aufgerufen werden. Ich werde eigentlich auch nur ein zweites anderes Beispiel posten, das keine Delegaten verwendet.

53voto

Jon Hess Punkte 14197

Hier ist ein Beispiel, das die Konzepte der Delegierten aus, und tut nur eine rohe zurückrufen.

@interface Foo : NSObject {
}
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end

@interface Bar : NSObject {
}
@end

@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector {
    /* do lots of stuff */
    [object performSelector:selector withObject:self];
}
@end

@implementation Bar
- (void)aMethod {
    Foo *foo = [[[Foo alloc] init] autorelease];
    [foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];
}

- (void)fooIsDone:(id)sender {
    NSLog(@"Foo Is Done!");
}
@end

Normalerweise wäre die Methode -[Foo doSomethingAndNotifyObject:withSelector:] asynchron, was den Callback nützlicher machen würde, als er hier ist.

1 Stimmen

Vielen Dank, John. Ich verstehe Ihre erste Callback-Implementierung nach Ihren Kommentaren. Auch Ihre 2. Callback-Implementierung ist unkomplizierter. Beide sind sehr gut.

1 Stimmen

Vielen Dank für diesen Beitrag, Jon, er war sehr hilfreich. Ich musste [object performSelectorwithObject:self]; in [object performSelector:selector withObject:self]; ändern, um es richtig zu machen.

18voto

Ryan Brodie Punkte 6366

Um diese Frage aktuell zu halten, wurde mit iOS 5.0 die ARC bedeutet, dass dies erreicht werden kann durch Blöcke noch prägnanter:

@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end

@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback {
    // Return a message to the callback
    callback(@"Hello to you too!");
}
@end

[Robot sayHi:^(NSString *reply){
  NSLog(@"%@", reply);
}];

Es gibt immer F****ng Block Syntax falls Sie jemals die Block-Syntax von Objective-C vergessen sollten.

0 Stimmen

In @interface sollte stehen + (void)sayHi:(void(^)(NSString *reply))callback; pas + (void)sayHi:(void(^)(NSString *))callback;

0 Stimmen

Nicht nach den oben genannten F****ng Block Syntax : - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName; (Anmerkung parameterTypes pas parameters )

5voto

Anil Gupta Punkte 1107

Rückruf: Es gibt 4 Arten von Rückrufen in Objective C

  1. Selektor-Typ : Sie können sehen, NSTimer, UIPangesture sind die Beispiele für Selector Callback. Wird für die sehr begrenzte Ausführung von Code verwendet.

  2. Delegierter Typ : Häufig und am häufigsten im Apple-Framework verwendet. UITableViewDelegate, NSNURLConnectionDelegate. Sie werden in der Regel verwendet, um das Herunterladen vieler Bilder vom Server asynchron zu zeigen usw.

  3. NSNotifications : NotificationCenter ist eine der Funktionen von Objective C, die dazu dient, viele Empfänger zu benachrichtigen, wenn ein Ereignis eintritt.

  4. Blöcke : Blöcke werden in der Objective-C-Programmierung häufiger verwendet. Sie sind eine großartige Funktion und werden für die Ausführung von Codeabschnitten verwendet. Sie können auch Tutorial zu verstehen, beziehen: Blöcke-Tutorial

Bitte lassen Sie mich wissen, wenn Sie eine andere Antwort dafür haben. Ich werde es zu schätzen wissen.

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