2

我是 Objective C 业务的新手(大部分时间是 Java 开发人员),现在正在开发我的第一个杀手级应用程序。:-) 目前我对使用选择器作为方法参数感到困惑。例如,它们似乎与 C# 中的委托有点不同。

给定以下方法签名

-(void)execute:(SEL)callback;

有没有办法强制传递给这种方法的选择器的签名?该方法需要具有以下签名的方法的选择器

-(void)foo:(NSData*)data;

但是 SEL(类型)是通用的,因此很有可能将错误的选择器传递给 execute方法。好的,至少在运行时会看到一个有趣的行为......但我希望在发生这种情况时看到编译器警告/错误。

4

3 回答 3

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];
于 2010-01-22T17:01:32.557 回答
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
}
于 2010-01-22T16:35:58.327 回答
0

如果要强制执行数据处理,请在选择器中使用 isKindOfClass。这很像您在 Java 中熟悉的 instanceof。

于 2010-01-22T16:32:11.293 回答