2

私は Objective C ビジネス (ほとんどの場合 Java 開発者) に不慣れで、今、最初のキラー アプリに取り組んでいます。:-) 現時点では、セレクターをメソッド引数として使用することについて、どういうわけか混乱しています。たとえば、C# のデリゲートとは少し異なるようです。

次のメソッド シグネチャが与えられた場合

-(void)execute:(SEL)callback;

そのようなメソッドに渡されるセレクターの署名を強制する方法はありますか? メソッドは、次のシグネチャを持つメソッドのセレクターを期待しています

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

ただし、SEL (タイプ) は汎用であるため、 executeメソッドに間違ったセレクターを渡す可能性が高くなり ます。少なくとも実行時にはおかしな動作が見られますが、これが発生したときにコンパイラの警告/エラーが表示されるようにしたいと思います。

4

3 に答える 3

6

SEL簡単な答えは次のとおりです。いいえ、引数を介して提供されるメソッドセレクターのメソッドシグネチャーをコンパイラーに強制させる方法はありません。

Objective-C の強みの 1 つは、より動的な動作を可能にする弱い型付けの言語であることです。もちろん、これにはコンパイル時の型の安全性が犠牲になります。

(私が思うに) やりたいことを行うには、デリゲートを使用するのが最善の方法です。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 に答える