Wie führe ich Rückruffunktionen in Objective-C aus?
Ich möchte nur einige fertige Beispiele sehen und ich sollte es verstehen.
Wie führe ich Rückruffunktionen in Objective-C aus?
Ich möchte nur einige fertige Beispiele sehen und ich sollte es verstehen.
Antworten:
Normalerweise werden Rückrufe in Ziel C mit Delegierten durchgeführt. Hier ist ein Beispiel für eine benutzerdefinierte Delegatenimplementierung.
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
Implementierungsdatei (.m)
@implementation MyClass
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate; /// Not retained
}
- (void)doSomething {
[delegate myClassWillDoSomething:self];
/* DO SOMETHING */
[delegate myClassDidDoSomething:self];
}
@end
Das zeigt den allgemeinen Ansatz. Sie erstellen eine Kategorie in NSObject, die die Namen Ihrer Rückrufmethoden deklariert. NSObject implementiert diese Methoden nicht. 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 Typensignatur des Selektors weiterzuleiten.
Als nächstes haben Sie ein Objekt, das der Delegat von "MyClass" ist, und MyClass ruft die Delegatmethoden für den Delegaten entsprechend auf. Wenn Ihre Delegaten-Rückrufe optional sind, schützen Sie sie normalerweise am Versandort mit "if ([Delegat antwortetToSelector: @selector (myClassWillDoSomething :)) {". In meinem Beispiel muss der Delegat beide Methoden implementieren.
Anstelle eines informellen Protokolls können Sie auch ein mit @protocol definiertes formelles Protokoll verwenden. Wenn Sie dies tun, ändern Sie den Typ des Delegatensetzers und der Instanzvariablen in " id <MyClassDelegate>
" anstatt nur " id
".
Außerdem werden Sie feststellen, dass der Delegat nicht beibehalten wird. Dies geschieht normalerweise, weil das Objekt, das Instanzen von "MyClass" "besitzt", normalerweise auch der Delegat ist. Wenn MyClass seinen Delegaten behalten würde, würde es einen Aufbewahrungszyklus geben. Bei der Dealloc-Methode einer Klasse mit einer MyClass-Instanz und ihrem Delegaten ist es eine gute Idee, diese Delegatenreferenz zu löschen, da es sich um einen schwachen Rückzeiger handelt. Andernfalls haben Sie einen baumelnden Zeiger, wenn etwas die MyClass-Instanz am Leben hält.
Der Vollständigkeit halber besteht die andere (neuere) Option darin, Blöcke zu verwenden, da StackOverflow RSS die Frage für mich nur zufällig wiederbelebt hat:
@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);
}];
Hier ist ein Beispiel, das die Konzepte von Delegierten fernhält und nur einen rohen Rückruf ausführt.
@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 ist die Methode - [Foo doSomethingAndNotifyObject: withSelector:] asynchron, was den Rückruf nützlicher macht als hier.
Um diese Frage auf dem neuesten Stand zu halten, bedeutet die Einführung von ARC in iOS 5.0, dass dies mithilfe von Blöcken noch präziser erreicht werden kann:
@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, wenn Sie jemals die Block Syntax von Objective-C vergessen haben.
+ (void)sayHi:(void(^)(NSString *reply))callback;
nicht sein+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(Anmerkung parameterTypes
nicht parameters
)
CallBack: In Ziel C gibt es 4 Arten von Rückrufen
Selektortyp : Sie können NSTimer sehen, UIPangesture sind die Beispiele für Selector-Rückruf. Wird für die sehr eingeschränkte Ausführung von Code verwendet.
Delegatentyp : Häufig und am häufigsten im Apple Framework verwendet. UITableViewDelegate, NSNURLConnectionDelegate. Sie werden normalerweise verwendet, um das asynchrone Herunterladen vieler Bilder vom Server usw. anzuzeigen.
Bitte lassen Sie mich, wenn eine andere Antwort darauf. Ich werde es zu schätzen wissen.