Как выполнять обратные вызовы в Objective-C


Как выполнять функции обратного вызова в Objective-C?

Я просто хотел бы увидеть некоторые завершенные примеры, и я должен понять это.

5 112

5 ответов:

обычно обратные вызовы в objective C выполняются с делегатами. Вот пример реализации пользовательского делегата;


Заголовочный Файл:

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

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

реализация (.м) файл

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

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

это иллюстрирует общий подход. Вы создаете категорию на NSObject, которая объявляет имена ваших методов обратного вызова. NSObject фактически не реализует эти методы. Этот тип категории называется неофициальным протоколом, вы просто говорите что многие объекты могут реализовать эти методы. Они являются способом переадресации объявления сигнатуры типа селектора.

Далее у вас есть какой-то объект быть делегатом "MyClass" и MyClass вызывает методы делегата на делегате соответствующим образом. Если ваши обратные вызовы делегата являются необязательными, вы обычно защищаете их на сайте отправки с помощью чего-то вроде " if ([delegate respondsToSelector:@selector(myClassWillDoSomething:)) {". В моем примере делегат необходим для реализации оба метода.

вместо неформального протокола можно также использовать формальный протокол, определенный с помощью @protocol. Если вы это сделаете, вы измените тип установщика делегата и переменную экземпляра на "id <MyClassDelegate>" вместо "id".

кроме того, вы заметите, что делегат не сохраняется. Обычно это делается потому, что объект, который "владеет" экземплярами "MyClass", обычно также является делегатом. Если MyClass сохранит свой делегат,то будет сохранен цикл. Это хорошая идея в методе dealloc класса, который имеет экземпляр MyClass и является его делегатом, чтобы очистить эту ссылку делегата, поскольку это слабый обратный указатель. В противном случае, если что-то поддерживает экземпляр MyClass, у вас будет висячий указатель.

для полноты, так как StackOverflow RSS просто случайно воскресил вопрос для меня, другой (более новый) вариант-использовать блоки:

@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);
}];

вот пример, который сохраняет понятия делегатов, и просто делает необработанный обратный вызов.

@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

обычно метод - [Foo doSomethingAndNotifyObject: withSelector:] будет асинхронным, что сделает обратный вызов более полезным, чем здесь.

чтобы сохранить этот вопрос в актуальном состоянии, введение iOS 5.0 в ARC значит это может быть достигнуто с помощью блоки еще более лаконично:

@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);
}];

всегда F****ng синтаксис блока Если вы когда-нибудь забудете синтаксис блока Objective-C.

обратный вызов: существует 4 типа обратного вызова в Objective C

  1. выбор типа : вы можете увидеть NSTimer, UIPangesture примеры обратного вызова селектора. Используется для очень ограниченного выполнения кода.

  2. Тип Делегата: общие и наиболее часто используемые в рамках Apple. UITableViewDelegate, NSNURLConnectionDelegate. Они обычно используются, чтобы показать загрузку многих изображений с сервера асинхронно так далее.

  3. NSNotifications : NotificationCenter является одной из особенностей Objective C, которая используется для уведомления многих получателей в то время, когда происходит событие.
  4. блоки : блоки чаще всего используются в программировании Objective C. Это отличная функция и используется для выполнения блока кода. Вы также можете обратиться к учебнику, чтобы понять:блоки уроке

пожалуйста, сообщите мне, если любой другой ответ на него. Я буду ценить это.