Je suis un novice iOS. J'ai une méthode de sélection comme suit -
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}
J'essaie de mettre en œuvre quelque chose comme ça -
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];
Mais cela me donne une erreur en disant -
Instance method -performSelector:withObject:withObject:afterDelay: not found
Des idées quant à ce qui me manque?
Personnellement, je pense que NSInvocation est une solution plus proche de vos besoins.
Quelque chose comme ce qui suit fera le travail:
( indexPath et dataSource sont deux variables d'instance définies dans la même méthode.
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];
}
Parce qu'il n'y a rien de tel qu'un [NSObject performSelector:withObject:withObject:afterDelay:]
méthode.
Vous devez encapsuler les données que vous souhaitez envoyer dans un seul objet Objective C (par exemple, un NSArray, un NSDictionary, un type d'objectif C personnalisé), puis les transmettre via the[NSObject performSelector:withObject:afterDelay:]
méthode connue et appréciée.
Par exemple:
NSArray * arrayOfThingsIWantToPassAlong =
[NSArray arrayWithObjects: @"first", @"second", nil];
[self performSelector:@selector(fooFirstInput:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:15.0];
Vous pouvez regrouper vos paramètres dans un seul objet et utiliser une méthode d'assistance pour appeler votre méthode d'origine, comme l'a suggéré Michael et d'autres à présent.
Une autre option est dispatch_after, qui prend un bloc et le met en file d'attente à un moment donné.
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];
});
Ou, comme vous l'avez déjà découvert, si vous n'avez pas besoin de délai, vous pouvez simplement utiliser - performSelector:withObject:withObject:
L'option la plus simple consiste à modifier votre méthode pour prendre un seul paramètre contenant les deux arguments, tel qu'un NSArray
ou NSDictionary
(ou ajouter une deuxième méthode prenant un seul paramètre, le décompresse et appelle la première méthode, puis appelez la méthode second avec un retard).
Par exemple, vous pourriez avoir quelque chose comme:
- (void) fooOneInput:(NSDictionary*) params {
NSString* param1 = [params objectForKey:@"firstParam"];
NSString* param2 = [params objectForKey:@"secondParam"];
[self fooFirstInput:param1 secondInput:param2];
}
Et puis pour l'appeler, vous pouvez faire:
[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
{
}
et appelez-le avec:
[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];
Vous pouvez trouver tous les types de méthodes performSelector: fournies fournies ici:
Il y a beaucoup de variations mais il n'y a pas de version prenant plusieurs objets aussi bien qu'un délai. Vous devrez plutôt encapsuler vos arguments dans un NSArray ou 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:
Je n'aime pas la méthode NSInvocation, trop complexe. Gardons les choses simples et propres:
// 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);
Je viens de faire quelques bruits et besoin d'appeler la méthode d'origine. Ce que j'ai fait a été de faire un protocole et jeté mon objet à cela. Une autre méthode consiste à définir la méthode dans une catégorie, mais nécessite la suppression d'un avertissement (le diagnostic #pragma clang est ignoré "-Wincomplete-implementation").
Un moyen simple et réutilisable est d’étendre NSObject
et d’implémenter
- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;
quelque chose comme:
- (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];
}
Je créerais simplement un objet personnalisé contenant tous mes paramètres en tant que propriétés, puis utiliserais cet objet unique en tant que paramètre.