私はiOS初心者です。私は次のようなセレクターメソッドを持っています-
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}
私はこのようなものを実装しようとしています-
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];
しかし、それは私に言ってエラーを与えます-
Instance method -performSelector:withObject:withObject:afterDelay: not found
私が何が欠けているかについてのアイデアはありますか?
個人的に、私はあなたのニーズにより近い解決策はNSInvocationの使用だと思います。
次のようなものが作業を行います:
indexPath and dataSourceは、同じメソッドで定義された2つのインスタンス変数です。
SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");
if([dropDownDelegate respondsToSelector:aSelector]) {
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
[inv setSelector:aSelector];
[inv setTarget:dropDownDelegate];
[inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv invoke];
}
[NSObject performSelector:withObject:withObject:afterDelay:]
メソッドのようなものはないからです。
送信するデータを単一のObjective Cオブジェクト(NSArray、NSDictionary、カスタムObjective C型など)にカプセル化してから、よく知られ、愛されている[NSObject performSelector:withObject:afterDelay:]
メソッドに渡す必要があります。
例えば:
NSArray * arrayOfThingsIWantToPassAlong =
[NSArray arrayWithObjects: @"first", @"second", nil];
[self performSelector:@selector(fooFirstInput:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:15.0];
パラメータを1つのオブジェクトにパッケージ化し、ヘルパーメソッドを使用して元のメソッドを呼び出すことができます。これは、Michaelや他の人が示唆しています。
別のオプションはdispatch_afterです。これはブロックを取得し、特定の時間にそれをキューに入れます。
double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self fooFirstInput:first secondInput:second];
});
または、すでに発見したように、遅延を必要としない場合は、- performSelector:withObject:withObject:
を使用できます
最も簡単なオプションは、NSArray
やNSDictionary
などの両方の引数を含む単一のパラメーターを取得するようにメソッドを変更することです(または、単一のパラメーターを取得してアンパックし、最初のメソッドを呼び出す2番目のメソッドを追加しますメソッド、そして遅延でsecondメソッドを呼び出します)。
たとえば、次のようなものがあります。
- (void) fooOneInput:(NSDictionary*) params {
NSString* param1 = [params objectForKey:@"firstParam"];
NSString* param2 = [params objectForKey:@"secondParam"];
[self fooFirstInput:param1 secondInput:param2];
}
そして、それを呼び出すには、次のことができます:
[self performSelector:@selector(fooOneInput:)
withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil]
afterDelay:15.0];
- (void) callFooWithArray: (NSArray *) inputArray
{
[self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}
そしてそれを次のように呼び出します:
[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
提供されているすべてのタイプのperformSelector:メソッドは、次の場所にあります。
たくさんのバリエーションがありますが、複数のオブジェクトと遅延を必要とするバージョンはありません。代わりに、NSArrayまたはNSDictionaryで引数をラップする必要があります。
- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject:
NSInvocationの方法は複雑すぎるのが嫌いです。シンプルできれいにしましょう:
// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;
// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];
// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);
スウィズルをいくつか実行しただけで、元のメソッドを呼び出す必要がありました。私がしたことは、プロトコルを作成し、オブジェクトをそれにキャストすることでした。別の方法は、カテゴリでメソッドを定義することですが、警告を抑制する必要があります(#pragma clang診断は「-Wincomplete-implementation」を無視します)。
シンプルで再利用可能な方法は、NSObject
を拡張して実装することです
- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;
何かのようなもの:
- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
[invocation setSelector: aSelector];
int index = 2; //0 and 1 reserved
for (NSObject *argument in arguments) {
[invocation setArgument: &argument atIndex: index];
index ++;
}
[invocation invokeWithTarget: self];
}
すべてのパラメーターをプロパティとして保持するカスタムオブジェクトを作成し、その単一のオブジェクトをパラメーターとして使用します