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

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

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

Ответ 1

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

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

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


/// Message (.m) File
@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 отвечаетSoSelector: @selector (myClassWillDoSomething:)) {". В моем примере делегат должен реализовать оба метода.

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

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

Ответ 2

Для полноты, поскольку 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);
}];

Ответ 3

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

@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:] будет асинхронным, что делает обратный вызов более полезным, чем он есть здесь.

Ответ 4

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

@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 Синтаксис блока.

Ответ 5

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

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

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

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

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