Быстрый ответ: нет, нет способа заставить компилятор принудительно использовать сигнатуру метода селектора метода, который предоставляется с помощью аргумента SEL
.
Одной из сильных сторон Objective-C является то, что это язык со слабой типизацией, который допускает гораздо более динамичное поведение. Конечно, это происходит за счет безопасности типов во время компиляции.
Для того, чтобы делать то, что (я думаю) вы хотите, лучше всего использовать делегатов. Какао использует делегаты, чтобы позволить другому классу реализовать методы типа «обратного вызова». Вот как это может выглядеть:
FooController.h
@protocol FooControllerDelegate
@required:
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
@end
@interface FooController : NSObject
{
id <FooControllerDelegate> * delegate;
}
@property (assign) id <FooControllerDelegate> * delegate;
- (void)doStuff;
@end
FooController.m
@interface FooController (delegateCalls)
- (void)handleData:(NSData *)data;
@end
@implementation FooController
@synthesize delegate;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
delegate = nil;
...
return self;
}
- (void)doStuff
{
...
[self handleData:data];
}
- (void)handleData:(NSData *)data
{
if (delegate != nil)
{
[delegate handleData:data forFoo:self];
}
else
{
return;
// or throw an error
// or handle it yourself
}
}
@end
Использование ключевого слова @required
в вашем протоколе делегата не позволит вам назначить делегата для FooController
, который не реализует метод точно так, как описано в протоколе. Попытка предоставить делегата, который не соответствует методу протокола @required
, приведет к ошибке компилятора.
Вот как вы должны создать класс делегата для работы с приведенным выше кодом:
@interface MyFooHandler <FooControllerDelegate> : NSObject
{
}
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
@end
@implementation MyFooHandler
- (void)handleData:(NSData *)data forFoo:(FooController *)foo
{
// do something here
}
@end
А вот как бы вы все использовали:
FooController * foo = [[FooController alloc] init];
MyFooHandler * fooHandler = [[MyFooHandler alloc] init];
...
[foo setDelegate:fooHandler]; // this would cause a compiler error if fooHandler
// did not implement the protocol properly
...
[foo doStuff]; // this will call the delegate method on fooHandler
...
[fooHandler release];
[foo release];