开发者

Method signature for a Selector

I'm new to the Objective C business (Java developer most of the time) and am woking on my first killer app now. :-) At the moment I am somehow confused about the usage of selectors as method arguments. They seem to be a little bit different than delegates in C# for example.

Given the following method signature

-(void)execute:(SEL)callback;

is there a way to enforce the signature for the selector passed to such a method? The method is expecting a selector of a method with the following signature

开发者_如何学C-(void)foo:(NSData*)data;

But the SEL (type) is generic, so there is a good chance to pass a wrong selector to the execute method. OK at least at runtime one would see a funny behavior... but I would like to see a compiler warning/error when this happens.


The quick answer is: no, there is no way to have the compiler enforce the method signature of a method selector that is provided via a SEL argument.

One of the strengths of Objective-C is that it is weakly-typed language, which allows for a lot more dynamic behaviour. Of course, this comes at the cost of compile-time type safety.

In order to do what (I think) you want, the best approach is to use delegates. Cocoa uses delegates to allow another class to implement "callback"-type methods. Here is how it might look:

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

Using the @required keyword in your delegate protocol will prevent you from assigning a delegate to a FooController that does not implement the method exactly as described in the protocol. Attempting to provide a delegate that does not match the @required protocol method will result in a compiler error.

Here is how you would create a delegate class to work with the above code:

@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

And here is how you would use everything:

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];


To directly answer your question, no, the SEL type allows any type of selector, not just ones with a specific signature.

You may want to consider passing an object instead of a SEL, and document that the passed object should respond to a particular message. For example:

- (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
}


If you want to enforce the data handling, use isKindOfClass inside your selector. This works a lot like instanceof which you are familiar with in Java.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜