La NSObject
méthode performSelector:withObject:afterDelay:
me permet d'invoquer une méthode sur l'objet avec un argument d'objet après un certain temps. Il ne peut pas être utilisé pour les méthodes avec un argument non-objet (par exemple ints, floats, structs, pointeurs non-objet, etc.).
Quelle est la manière la plus simple de réaliser la même chose avec une méthode avec un argument non-objet? Je sais que pour les réguliers performSelector:withObject:
, la solution est d'utiliser NSInvocation
(ce qui d'ailleurs est vraiment compliqué). Mais je ne sais pas comment gérer la partie "delay".
Merci,
objective-c
cocoa
user102008
la source
la source
Réponses:
Voici ce que j'appelais quelque chose que je ne pouvais pas changer en utilisant NSInvocation:
la source
[theMovie setOrientation: UIInterfaceOrientationPortrait animated:NO]
? Ou voulez-vous dire que leinvoke
message est dans la méthode que vous exécutez après le délai?Enveloppez simplement le float, boolean, int ou similaire dans un NSNumber.
Pour les structures, je ne connais pas de solution pratique, mais vous pouvez créer une classe ObjC distincte qui possède une telle structure.
la source
nil
pour qu'unBOOL
paramètre reçoiveNO
(FALSE
)N'UTILISEZ PAS CETTE RÉPONSE. JE L'AI QUITTER UNIQUEMENT POUR DES FINS HISTORIQUES. VOIR LES COMMENTAIRES CI-DESSOUS.
Il y a une astuce simple s'il s'agit d'un paramètre BOOL.
Passez nul pour NON et auto pour OUI. nil est converti en valeur BOOL de NO. self est converti à la valeur BOOL de YES.
Cette approche se décompose s'il s'agit d'autre chose qu'un paramètre BOOL.
En supposant que le soi est un UIView.
la source
if ()
test dessus, mais il est concevable que certains codes dépendent de 0 ou 1, et donc gagné Ne considérez pas une grande valeur d'adresse comme étant la même que 1 (OUI).self
avec une adresse comme0x0123400
. Avec cette approche, vous obtiendrez NON insted de OUI dans 0,4% des cas. Pire, avec cette probabilité, cette solution peut passer tous les tests et se révèle plus tard.Peut-être NSValue , assurez-vous simplement que vos pointeurs sont toujours valides après le délai (c'est-à-dire qu'aucun objet n'est alloué sur la pile).
la source
NSValue
(si possible) à l'attendutype
?Je sais que c'est une vieille question, mais si vous créez le SDK iOS 4+, vous pouvez utiliser des blocs pour le faire avec très peu d'effort et le rendre plus lisible:
la source
PerformSelector: WithObject prend toujours un objet, donc pour passer des arguments comme int / double / float etc ..... Vous pouvez utiliser quelque chose comme ça.
De la même manière, vous pouvez utiliser [NSNumber numberWithInt:] etc .... et dans la méthode de réception, vous pouvez convertir le nombre dans votre format comme [nombre entier] ou [nombre double].
la source
Les blocs sont la voie à suivre. Vous pouvez avoir des paramètres complexes, taper la sécurité, et c'est beaucoup plus simple et plus sûr que la plupart des anciennes réponses ici. Par exemple, vous pouvez simplement écrire:
Les blocs vous permettent de capturer des listes de paramètres arbitraires, des objets de référence et des variables.
Mise en œuvre de support (de base):
Exemple:
Voir également la réponse de Michael (+1) pour un autre exemple.
la source
Je recommanderais toujours que vous utilisiez NSMutableArray comme objet à transmettre. En effet, vous pouvez ensuite passer plusieurs objets, comme le bouton enfoncé et d'autres valeurs. NSNumber, NSInteger et NSString ne sont que des conteneurs d'une certaine valeur. Assurez-vous que lorsque vous obtenez l'objet du tableau auquel vous faites référence, un type de conteneur correct. Vous devez transmettre les conteneurs NS. Là, vous pouvez tester la valeur. N'oubliez pas que les conteneurs utilisent isEqual lorsque les valeurs sont comparées.
la source
Je voulais aussi faire cela, mais avec une méthode qui reçoit un paramètre BOOL. Enveloppant la valeur booléenne avec NSNumber, ÉCHEC DE PASSER LA VALEUR. Je ne sais pas pourquoi.
J'ai donc fini par faire un simple hack. J'ai mis le paramètre requis dans une autre fonction factice et j'appelle cette fonction en utilisant performSelector, où withObject = nil;
la source
-performSelector[...]
méthode attend un objet (au lieu d'un type de données primitif), et qu'elle ne sait pas que le sélecteur appelé accepte un booléen, peut-être que l'adresse (valeur du pointeur) de l'NSNumber
instance est aveuglément `` cast '' enBOOL
(= non nul, c'est-à-direTRUE
). Peut-être que le runtime pourrait être plus intelligent que cela et reconnaître un zéro booléen enveloppé dans unNSNumber
!Je trouve que le moyen le plus rapide (mais un peu sale) de le faire est d'appeler directement objc_msgSend. Cependant, il est dangereux de l'invoquer directement car vous devez lire la documentation et vous assurer que vous utilisez la bonne variante pour le type de valeur de retour et parce que objc_msgSend est défini comme vararg pour la commodité du compilateur mais est en fait implémenté comme colle d'assemblage rapide . Voici du code utilisé pour appeler une méthode déléguée - [delegate integerDidChange:] qui prend un seul argument entier.
Cela enregistre d'abord le sélecteur car nous allons y faire référence plusieurs fois et il serait facile de créer une faute de frappe. Il vérifie ensuite que le délégué répond réellement au sélecteur - il peut s'agir d'un protocole facultatif. Il crée ensuite un type de pointeur de fonction qui spécifie la signature réelle du sélecteur. Gardez à l'esprit que tous les messages Objective-C ont deux premiers arguments cachés, l'objet étant envoyé et le sélecteur envoyé. Ensuite, nous créons un pointeur de fonction du type approprié et le définissons pour qu'il pointe vers la fonction objc_msgSend sous-jacente. Gardez à l'esprit que si la valeur de retour est un float ou un struct, vous devez utiliser une variante différente de objc_msgSend. Enfin, envoyez le message en utilisant le même mécanisme qu'Objective-C utilise sous les feuilles.
la source
Vous pouvez simplement utiliser NSTimer pour appeler un sélecteur:
la source
yourMethod:
dans votre exemple est le minuteur lui-même, et vous n'avez rien transmis pouruserInfo
. Même si vous aviez utiliséuserInfo
, vous auriez toujours à réduire la valeur, comme le suggéra Remus Rusanu.L'appel de performSelector avec un NSNumber ou une autre NSValue ne fonctionnera pas. Au lieu d'utiliser la valeur de NSValue / NSNumber, il convertira efficacement le pointeur en un int, float ou autre et l'utilisera.
Mais la solution est simple et évidente. Créez le NSInvocation et appelez
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay]
la source
Peut-être ... ok, très probablement, il me manque quelque chose, mais pourquoi ne pas simplement créer un type d'objet, disons NSNumber, en tant que conteneur de votre variable de type non-objet, telle que CGFloat?
la source