Puis-je faire un NSMutableArray où tous les éléments sont de type SomeClass ?
Réponses
Trop de publicités?Ce qui est relativement commun de question pour les personnes en transition de fortement du type de langages (comme C++ ou Java) de plus en plus faiblement ou typées dynamiquement des langages comme Python, Ruby, ou Objective-C Objective-C, la plupart des objets héritent de NSObject
(type id
) (le reste hériter d'une autre classe racine comme NSProxy
et peut également être de type id
), et un message peut être envoyé à n'importe quel objet. Bien sûr, l'envoi d'un message à une instance qu'il ne reconnaît pas peut provoquer une erreur d'exécution (et aussi à cause d'un compilateur d'avertissement appropriés -W drapeaux). Tant qu'une instance répond au message que vous envoyez, vous ne se soucient pas quelle classe il appartient. Ceci est souvent appelé "duck typing" car "s'il charlatans comme un canard [c'est à dire qui répond à un sélecteur], c'est un canard [c'est à dire qu'il peut gérer le message; qui se soucie de ce que la classe qu'il est]".
Vous pouvez tester si une instance répond à un sélecteur au moment de l'exécution avec l' -(BOOL)respondsToSelector:(SEL)selector
méthode. En supposant que vous voulez l'appeler une méthode sur tous les cas dans un tableau mais ne sont pas sûr que toutes les instances peuvent gérer le message (vous ne pouvez pas utiliser NSArray
s' -[NSArray makeObjectsPerformSelector:]
, quelque chose de ce genre:
for(id o in myArray) {
if([o respondsToSelector:@selector(myMethod)]) {
[o myMethod];
}
}
Si vous contrôlez le code source pour les instances à mettre en œuvre la ou les méthode(s) que vous souhaitez appeler, l'approche plus commune serait de définir un @protocol
qui contient ces méthodes et de déclarer que les classes en question, de mettre en œuvre ce protocole dans leur déclaration. Dans cette utilisation, @protocol
est analogue à une Interface Java ou en C++ une classe de base abstraite. Vous pouvez ensuite tester la conformité de l'ensemble du protocole plutôt que de répondre à chaque méthode. Dans l'exemple précédent, il ne fera pas beaucoup de différence, mais si vous étiez en appelant plusieurs méthodes, il pourrait simplifier les choses. L'exemple serait alors:
for(id o in myArray) {
if([o conformsToProtocol:@protocol(MyProtocol)]) {
[o myMethod];
}
}
en supposant MyProtocol
déclare myMethod
. Cette seconde approche est favorisée, car elle précise l'intention du code plus que le premier.
Souvent, l'une de ces approches vous libère de s'inquiéter de savoir si tous les objets dans un tableau sont d'un type donné. Si vous n'avez toujours des soins, la dynamique de la langue est l'approche de test unitaire, test unitaire, test d'unité. En raison d'une régression dans cette exigence de produire un (probablement irrécupérable) runtime (pas le temps de compilation) erreur, vous avez besoin de la couverture de test pour vérifier le comportement de sorte que vous ne relâchez pas un coup retentissant dans la nature. Dans ce cas, d'effectuer une opération qui modifie le tableau, puis vérifiez que toutes les instances dans le tableau appartiennent à une classe donnée. Avec une bonne couverture de test, vous n'avez même pas besoin de l'ajout gestion d'exécution de la vérification de l'instance de l'identité. Vous avez une bonne couverture de tests unitaires, n'est-ce pas?
Vous pourriez faire une catégorie avec un -addSomeClass:
méthode pour permettre la compilation statique type de vérification (de sorte que le compilateur pourrait vous permettre de savoir si vous essayez d'ajouter un objet qu'il connaît, c'est une autre classe par le biais de la méthode), mais il n'y a pas de véritable moyen de faire valoir un tableau ne contient que des objets d'une classe donnée.
En général, il ne semble pas être une nécessité pour une telle contrainte en Objective-C. je ne pense pas que j'ai jamais entendu une expérience de Cacao programmeur souhaite pour cette fonction. Les seules personnes qui semblent sont les programmeurs à partir d'autres langues qui sont encore à penser dans ces langues. Si vous ne souhaitez que des objets d'une classe donnée dans un tableau, seulement coller des objets de cette classe là. Si vous voulez tester votre code fonctionne correctement, le tester.
Vous pourriez sous-classe NSMutableArray
d'appliquer le type de sécurité.
NSMutableArray
est une classe de cluster, sorte de sous-classement n'est pas trivial. J'ai fini par hériter de NSArray
et transmis les invocations d'un tableau à l'intérieur de cette classe. Le résultat est une classe appelée ConcreteMutableArray
qui est facile à la sous-classe. Voici ce que j'ai trouvé:
Mise à jour: la caisse de ce billet de blog de Mike Cendres sur sous-classement d'une classe de cluster.
Inclure ces fichiers dans votre projet, puis de générer tous les types que vous le souhaitez à l'aide de macros:
MyArrayTypes.h
CUSTOM_ARRAY_INTERFACE(NSString)
CUSTOM_ARRAY_INTERFACE(User)
MyArrayTypes.m
CUSTOM_ARRAY_IMPLEMENTATION(NSString)
CUSTOM_ARRAY_IMPLEMENTATION(User)
Utilisation:
NSStringArray* strings = [NSStringArray array];
[strings add:@"Hello"];
NSString* str = [strings get:0];
[strings add:[User new]]; //compiler error
User* user = [strings get:0]; //compiler error
D'Autres Pensées
- Il hérite d'
NSArray
à l'appui de la sérialisation/désérialisation -
Selon votre goût, vous souhaiterez peut-être modifier/masquer les méthodes génériques comme
- (void) addObject:(id)anObject
Jetez un oeil à https://github.com/tomersh/Objective-C-Generics, une implémentation de compilation (implémenté preprocessor) génériques pour Objective-C. Ce blog a un bel aperçu. Fondamentalement, vous obtenez compilation vérification (avertissements ou erreurs), mais aucune pénalité de runtime pour les médicaments génériques.
Ce projet Github implémente exactement cette fonctionnalité.
Vous pouvez ensuite utiliser les `` entre crochets, comme vous le feriez en c#.
De leurs exemples :