Как выполнять обратные вызовы в Objective-C - PullRequest
115 голосов
/ 19 июня 2009

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

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

Ответы [ 5 ]

135 голосов
/ 12 октября 2010

Для полноты картины, поскольку 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);
}];
93 голосов
/ 19 июня 2009

Обычно обратные вызовы в задаче 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

Файл реализации (.m)

@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 ([делегат respdsToSelector: @selector (myClassWillDoSomething :)) {». В моем примере делегат требуется для реализации обоих методов.

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

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

49 голосов
/ 20 июня 2009

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

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

7 голосов
/ 31 марта 2016

Чтобы поддерживать актуальность этого вопроса, введение в 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.

3 голосов
/ 13 октября 2016

CallBack: в Objective C

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...