WedX - журнал о программировании и компьютерных науках

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

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

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


Ответы:


1

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

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

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

19.06.2009
  • +1 Хороший обстоятельный ответ. Глазурь на торте была бы ссылкой на более подробную документацию Apple по делегатам. :-) 19.06.2009
  • Джон, большое спасибо за вашу помощь. Я действительно ценю твою помощь. Я сожалею об этом, но я не совсем ясен в ответе. Message .m - это класс, который устанавливает себя в качестве делегата во время вызова функции doSomething. Является ли doSomething функцией обратного вызова, которую вызывает пользователь? поскольку у меня сложилось впечатление, что пользователь вызывает doSomething, а ваши функции обратного вызова - это myClassWillDoSomethingg и myClassDidDoSomething. Также не могли бы вы показать мне, как создать более высокий класс, который вызывает функцию обратного вызова. Я программист на C, поэтому пока не слишком хорошо знаком со средой Obj-C. 19.06.2009
  • Сообщение .m просто означало, что в вашем файле .m. У вас был бы отдельный класс, назовем его Foo. Foo будет иметь переменную MyClass * myClass, и в какой-то момент Foo скажет [myClass setDelegate: self]. В любой момент после этого, если кто-либо, включая foo, вызовет doSomethingMethod в этом экземпляре MyClass, foo вызовет свои методы myClassWillDoSomething и myClassDidDoSomething. На самом деле я также просто опубликую второй пример, в котором не используются делегаты. 20.06.2009
  • Я не думаю, что .m означает сообщение. 20.06.2009
  • Интересно, я всегда думал об этом как о сообщении, но в Интернете похоже, что люди говорят либо о методе, либо о реализации. 20.06.2009
  • stackoverflow .com / questions / 652186 / 12.10.2010
  • Я сделал это для своего класса objective-c, как я могу быстро использовать его, чтобы получать обратные вызовы от objective-c? 14.03.2018

  • 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);
    }];
    
    12.10.2010
  • @Ahruman: Что означает ^ -символ в void (^ _completionHandler) (int someParameter); значит? Не могли бы вы объяснить, что делает эта строчка? 09.02.2012
  • Не могли бы вы объяснить, почему вам нужно копировать обработчик обратного вызова? 25.08.2015

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

    19.06.2009
  • Большое спасибо, Джон. Я понимаю вашу первую реализацию обратного вызова после ваших комментариев. Кроме того, ваша вторая реализация обратного вызова более проста. Оба очень хороши. 23.06.2009
  • Спасибо, что разместил это, Джон, это было очень полезно. Мне пришлось изменить [object performSelectorwithObject: self]; to [объект performSelector: селектор withObject: self]; чтобы заставить его работать правильно. 12.10.2010

  • 4

    Чтобы постоянно обновлять этот вопрос, введение в 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);
    }];
    

    Всегда есть Чертов синтаксис блока, если вы когда-нибудь забудете синтаксис блока Objective-C.

    31.03.2016
  • В @interface должно быть + (void)sayHi:(void(^)(NSString *reply))callback;, а не + (void)sayHi:(void(^)(NSString *))callback; 31.03.2016
  • Не в соответствии с вышеупомянутым синтаксисом блока F **** ng: - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName; (примечание parameterTypes не parameters) 31.03.2016

  • 5

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

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

    2. Тип делегата: распространенный и наиболее часто используемый в платформе Apple. Уитаблевиевделегате, НСНУРЛКоннектионделегате. Обычно они используются для демонстрации асинхронной загрузки множества изображений с сервера и т. Д.

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

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

    13.10.2016
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]