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