Как выполнять функции обратного вызова в Objective-C?
Я просто хотел бы увидеть несколько завершенных примеров и должен это понять.
Как выполнять функции обратного вызова в Objective-C?
Я просто хотел бы увидеть несколько завершенных примеров и должен это понять.
Обычно обратные вызовы в цели 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, у вас будет висячий указатель.
Для полноты, поскольку 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);
}];
Всегда есть Чертов синтаксис блока, если вы когда-нибудь забудете синтаксис блока Objective-C.
+ (void)sayHi:(void(^)(NSString *reply))callback;
, а не + (void)sayHi:(void(^)(NSString *))callback;
31.03.2016 - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(примечание parameterTypes
не parameters
) 31.03.2016 Обратный вызов: в Objective C есть 4 типа обратного вызова
Тип селектора. Вы можете видеть, что NSTimer и UIPangesture являются примерами обратного вызова селектора. Используется для очень ограниченного выполнения кода.
Тип делегата: распространенный и наиболее часто используемый в платформе Apple. Уитаблевиевделегате, НСНУРЛКоннектионделегате. Обычно они используются для демонстрации асинхронной загрузки множества изображений с сервера и т. Д.
Пожалуйста, дайте мне еще один ответ. Я буду признателен.