Jak wykonywać funkcje oddzwaniania w Objective-C?
Chciałbym tylko zobaczyć kilka ukończonych przykładów i powinienem to zrozumieć.
Jak wykonywać funkcje oddzwaniania w Objective-C?
Chciałbym tylko zobaczyć kilka ukończonych przykładów i powinienem to zrozumieć.
Odpowiedzi:
Zwykle wywołania zwrotne w celu C są wykonywane z delegatami. Oto przykład niestandardowej implementacji delegata;
Plik nagłówkowy:
@interface MyClass : NSObject {
id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end
@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end
Plik implementacji (.m)
@implementation MyClass
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate; /// Not retained
}
- (void)doSomething {
[delegate myClassWillDoSomething:self];
/* DO SOMETHING */
[delegate myClassDidDoSomething:self];
}
@end
To ilustruje ogólne podejście. Tworzysz kategorię na NSObject, która deklaruje nazwy twoich metod wywołania zwrotnego. NSObject w rzeczywistości nie implementuje tych metod. Ten typ kategorii nazywa się protokołem nieformalnym, po prostu mówisz, że wiele obiektów może implementować te metody. Są sposobem na przekazanie dalej deklaracji typu selektora.
Następnie masz jakiś obiekt będący delegatem „MyClass” i MyClass wywołuje metody delegata na delegacie, jeśli jest to wymagane. Jeśli wywołania zwrotne Twojego delegata są opcjonalne, zazwyczaj będziesz ich strzegł w miejscu wysyłki za pomocą czegoś takiego jak „if ([delegate respondsToSelector: @selector (myClassWillDoSomething :)) {". W moim przykładzie delegat musi zaimplementować obie metody.
Zamiast nieformalnego protokołu można również użyć formalnego protokołu zdefiniowanego za pomocą @protocol. Jeśli to zrobisz, zmienisz typ metody ustawiającej delegata i zmiennej instancji na „ id <MyClassDelegate>
” zamiast tylko „ id
”.
Zauważysz również, że delegat nie jest zatrzymany. Dzieje się tak zazwyczaj, ponieważ obiekt, który jest „właścicielem” wystąpień „MyClass”, jest zazwyczaj również delegatem. Gdyby MyClass zachował swojego delegata, wystąpiłby cykl przechowywania. W metodzie dealloc klasy, która ma instancję MyClass i jest jej delegatem, dobrym pomysłem jest wyczyszczenie odwołania do delegata, ponieważ jest to słaby wskaźnik wsteczny. W przeciwnym razie, jeśli coś utrzymuje instancję MyClass przy życiu, będziesz mieć wiszący wskaźnik.
Dla kompletności, ponieważ StackOverflow RSS po prostu losowo wskrzesił pytanie dla mnie, drugą (nowszą) opcją jest użycie bloków:
@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);
}];
Oto przykład, który usuwa koncepcje delegatów i po prostu wykonuje nieprzetworzone wywołanie zwrotne.
@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
Zazwyczaj metoda - [Foo doSomethingAndNotifyObject: withSelector:] byłaby asynchroniczna, co uczyniłoby wywołanie zwrotne bardziej użytecznym niż tutaj.
Aby to pytanie było aktualne, wprowadzenie ARC w iOS 5.0 oznacza, że można to osiągnąć za pomocą Blocks jeszcze bardziej zwięźle:
@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);
}];
Zawsze jest F **** ng Block Składnia, jeśli kiedykolwiek zapomnisz składni Block Objective-C.
+ (void)sayHi:(void(^)(NSString *reply))callback;
nie+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(Uwaga parameterTypes
nie parameters
)
CallBack: istnieją 4 typy wywołań zwrotnych w celu C
Typ selektora : możesz zobaczyć NSTimer, UIPangesture to przykłady wywołania zwrotnego selektora. Używany do bardzo ograniczonego wykonywania kodu.
Typ delegata : typowy i najczęściej używany w środowisku Apple. UITableViewDelegate, NSNURLConnectionDelegate. Zwykle są używane do wyświetlania asynchronicznego pobierania wielu obrazów z serwera itp.
Proszę, pozwól mi odpowiedzieć na to pytanie. Docenię to.