Wie führt man Callback-Funktionen in Objective-C aus?
Ich möchte nur ein paar fertige Beispiele sehen, dann sollte ich es verstehen.
Wie führt man Callback-Funktionen in Objective-C aus?
Ich möchte nur ein paar fertige Beispiele sehen, dann sollte ich es verstehen.
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);
}];
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 Gute und ausführliche Antwort. Das i-Tüpfelchen wäre ein Link zu einer ausführlicheren Apple-Dokumentation über Delegierte :-)
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.
"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.
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.
Vielen Dank, John. Ich verstehe Ihre erste Callback-Implementierung nach Ihren Kommentaren. Auch Ihre 2. Callback-Implementierung ist unkomplizierter. Beide sind sehr gut.
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.
In @interface sollte stehen + (void)sayHi:(void(^)(NSString *reply))callback;
pas + (void)sayHi:(void(^)(NSString *))callback;
Nicht nach den oben genannten F****ng Block Syntax : - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(Anmerkung parameterTypes
pas parameters
)
Rückruf: Es gibt 4 Arten von Rückrufen in Objective C
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.
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.
NSNotifications : NotificationCenter ist eine der Funktionen von Objective C, die dazu dient, viele Empfänger zu benachrichtigen, wenn ein Ereignis eintritt.
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 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.