我是Objective C业务的新手(大部分时间都是Java开发人员),现在正在使用我的第一个杀手级应用程序。 :-) 目前,我对选择器作为方法参数的使用感到困惑。它们似乎与C#中的代表有点不同。
给出以下方法签名
-(void)execute:(SEL)callback;
有没有办法强制执行传递给这种方法的选择器的签名? 该方法期望具有以下签名的方法的选择器
-(void)foo:(NSData*)data;
但是SEL(type)是通用的,所以很有可能将错误的选择器传递给 执行方法。好吧,至少在运行时,人们会看到一个有趣的行为......但是我希望在发生这种情况时看到编译器警告/错误。
答案 0 :(得分:6)
快速回答是:不,没有办法让编译器强制执行通过SEL
参数提供的方法选择器的方法签名。
Objective-C的一个优点是它是弱类型语言,它允许更多动态行为。当然,这是以编译时类型安全为代价的。
为了做你想做的事(我认为),最好的方法是使用代表。 Cocoa使用委托允许另一个类实现“回调”类型的方法。以下是它的外观:
<强> 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];
答案 1 :(得分:2)
要直接回答您的问题,不,SEL
类型允许任何类型的选择器,而不仅仅是具有特定签名的选择器。
您可能需要考虑传递对象而不是SEL
,并记录传递的对象应该响应特定的消息。例如:
- (void)execute:(id)object
{
// Do the execute stuff, then...
if ([object respondsToSelector:@selector(notifyOnExecute:)]) {
[object notifyOnExecute:self];
}
// You could handle the "else" case here, if desired
}
答案 2 :(得分:0)
如果要强制执行数据处理,请在选择器中使用isKindOfClass。这很像你在Java中熟悉的instanceof。