web-dev-qa-db-ja.com

SEL performSelectorと引数

SELオブジェクトしかない場合、いくつかの引数を持つセレクターを呼び出す簡単な方法があるはずです。正しい構文が見つからないようです。

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent
{
   int i =10;
   [parent performSelector:sel:i  ];
}
28
madmik3

NSObject のドキュメントをご覧ください。この場合:

_[parent performSelector:sel withObject:[NSNumber numberWithInt:i]];
_

(このメソッドは実際には NSObject protocol のドキュメントに記載されています)。 _-[NSObject performSelector:withObject:]_にはオブジェクト引数が必要なため、次のように親のクラスにラッパーを記述する必要があります

_-(void)myMethodForNumber:(NSNumber*)number {
    [self myMethod:[number intValue]];
}
_

NSNumberを開梱する。

非オブジェクト引数を直接受け取るメソッドを呼び出したい場合(たとえば、呼び出し先のソースを制御しておらず、カテゴリを追加したくない場合)は、 NSInvocation

_NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:parent];
[inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv invoke];
_

余談ですが、メソッドはinitメソッドのように見えますが、Objective-Cの正しい初期化子パターンに従っていません。スーパークラスの初期化子を呼び出す必要があり、その呼び出しからのnil結果をテストする必要があり、初期化子メソッドからselfを返す必要があります。すべての場合において、Objective-C初期化メソッドは次のようになります。

_-(id)myInitMethod {
    self = [super init];
    if(self != nil) {
      //perform initialization of self
    }

    return self;
}
_

その場合、メソッド(initメソッドの場合)は次のようになります。

_-(id) init: (SEL)sel owner:(NSObject*) parent
{
   self = [super init];
   if(self != nil) {
       int i = 10;
       NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
       [inv setSelector:sel];
       [inv setTarget:parent];
       [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
       [inv invoke];
   }

    return self;
}
_

よりObjective-Cになるように、イニシャライザの名前を-(id)initWithSelector:owner:にも変更します。

76
Barry Wark

バリー・ワークが言ったことは素晴らしいです。私は怠惰なプログラマーのための議論を変更しました

-(void)myMethodWith:(int)number andBOOL:(BOOL) someBool andStr:(NSString *)str{
    NSLog(@"%d %d %@",number,someBool,str);
}

-(void) testMethod{
    SEL sel = @selector(myMethodWith:andBOOL:andStr:);
    int i = 10;
    BOOL bol = YES;
    NSString *str = @"hey baby !";
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
    [inv setSelector:sel];
    [inv setTarget:self];
    [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&bol atIndex:3];
    [inv setArgument:&str atIndex:4];
    [inv invoke];
}
12
yunas

performSelector:withObject:を使用したいトリッキーな部分はintをNSObjectに変換することです。 performSelectorパラメータを使用するメッセージでintを使用することはできません。代わりにidを使用する必要があります。

NSObject Protocol Reference から:

aSelectorは、タイプidの単一の引数を取るメソッドを識別する必要があります。他の引数タイプと戻り値を持つメソッドの場合は、 NSInvocation を使用します。

その変更が行われると、次のことができます。

id arg = [NSNumber numberWithInt:10];    
[parent performSelector:sel withObject:arg];
3
Frank Krueger

id型の1つまたは2つのオブジェクトを引数として取るメソッドの場合、次を使用できます。

[parent performSelector:sel withObject:argument1];

または

[parent performSelector:sel withObject:argument1 withObject:argument2];

他の引数タイプのメソッドの場合、任意のメソッド呼び出しをカプセル化できるNSInvocationを作成します。

1
Ole Begemann

以下を使用できます。

- (id)performSelector:(SEL)aSelector withObject:(id)anObject
- (id)performSelector:(SEL)aSelector withObject:(id)anObject  withObject:(id)anotherObject

または、より複雑なメソッドを使用する必要がある場合は、NSInvocationクラスを使用します

1
Skie