web-dev-qa-db-fra.com

Existe-t-il une liste générique dans Cocoa/Objective-C?

Ce que j'aime vraiment en C #, ce sont les listes génériques. Une liste qui ne peut contenir qu'un seul type d'objets. Existe-t-il une liste générique dans Cocoa/Objective-C? Pour autant que je sache seulement NSArray qui va prendre un pointeur sur un objet.

30
TalkingCode

Vouloir cela dans une application Cocoa est souvent le signe d'un design faible.

NSArray est immuable, il ne "prend donc pas le pointeur sur un objet" et contient probablement les objets appropriés lorsqu'il vous est remis. Ce qui, je suppose, vous inquiète davantage est une NSMutableArray dans laquelle vous pensez que d'autres parties de votre code pourraient ajouter le mauvais type d'objet. Mais jetez un coup d'oeil au cacao lui-même; Il est extrêmement rare d'exposer un tableau mutable dans le cadre de la conception d'une classe.

Au lieu de cela, vous exposez généralement une NSArray et quelques méthodes pour modifier ce tableau. Quelque chose dans le genre de:

@class Foo : NSObject
- (NSArray *)bars;
- (void)addBar:(Bar *)bar;
- (void)removeBar:(Bar *)bar;
@end

Cela empêche généralement les objets erronés d'être insérés simplement en ayant un avertissement du compilateur, et vous pouvez bien sûr ajouter des assertions dans -addBar: et -removeBar: si vous le souhaitez.

34
Mike Abdullah

Objective-C ne supporte pas la programmation générique. Vous pouvez toujours utiliser Objective-C++ et une liste STL.

9
Ferruccio

Les NSArrays génériques peuvent être réalisés en sous-classant NSArray et en redéfinissant toutes les méthodes fournies avec des méthodes plus restrictives. Par exemple, 

- (id)objectAtIndex:(NSUInteger)index

devrait être redéfini dans

@interface NSStringArray : NSArray

comme

- (NSString *)objectAtIndex:(NSUInteger)index

pour qu'un NSArray ne contienne que NSStrings.

La sous-classe créée peut être utilisée comme remplacement immédiat et apporte de nombreuses fonctionnalités utiles: avertissements du compilateur, accès aux propriétés, meilleure création de code et complétion dans Xcode. Toutes ces fonctionnalités sont compilées, il n'est pas nécessaire de redéfinir l'implémentation réelle - les méthodes de NSArray peuvent toujours être utilisées.

Il est possible d'automatiser cela et de le réduire à deux déclarations, ce qui la rapproche des langages prenant en charge les génériques. J'ai créé une automatisation avec WMGenericCollection , où les modèles sont fournis sous forme de macros de préprocesseur.

Après avoir importé le fichier d'en-tête contenant la macro, vous pouvez créer un NSArray générique avec deux instructions: une pour l'interface et une pour l'implémentation. Vous devez uniquement fournir le type de données que vous souhaitez stocker et les noms de vos sous-classes. WMGenericCollection fournit de tels modèles pour NSArray, NSDictionary et NSSet, ainsi que leurs équivalents mutables.

3
w-m

Non, Objective-C ne prend actuellement pas en charge le typage paramétrique pour les éléments de collection.

Cependant, ce sujet est plus complexe que la question ou les réponses existantes ne l’admettent.

Le typage paramétrique pour les collections en Objective-C ne serait pas identique aux génériques en C #/Java. Par exemple, il est peu probable que Objective-C ajoute la capacité de vérifier que chaque objet ajouté à une collectionESTun type ou un sous-type NSArray. Au lieu de cela, Objective-C pourrait (et l’OMI devrait) avoir la capacité d’assurer chaque objet d’une collectionSE CONFORMEà un protocole/une interface. (c'est-à-dire qu'il implémente un ensemble de méthodes requises)

Pourquoi?

Objective-C est un langage construit sur la compatibilité de protocole (interface), PAS de relations de sous-typage. C'est-à-dire que les objets sont compatibles s'ils ont toutes les bonnes méthodes, nous ne regardons pas ou ne nous soucions pas de leurs types réels. En fait, regarder des types réels est une très très mauvaise pratique dans Obj-C et dans les plus découragés. Cette notion est parfois appelée "Duck Typing", parce que si elle se comporte comme un canard, c'est un canard. Peu nous importe qu'il hérite littéralement d'un canard spécifique ou non. Cela vous évite d'être harcelé par la hiérarchie d'implémentation de quelqu'un d'autre. - Le résultat est que tant qu'un objet sortant de la liste a une méthode draw :: ça marche, peu importe si c'est une sous-classe d'un objet spécifique de JimmyDrawableBase. 

Cela non seulement rend le code plus réutilisable, mais encourage également un type de décomposition de problème légèrement différent (plus fonctionnel?), Car vous ne pouvez pas compter sur des objets dérivés d'une classe de base donnée et disposant ainsi d'un groupe de votre classe de base. mise en œuvre forcée dans eux.

Je pense personnellement que ce serait Nice que le compilateur Obj-C ait un contrôle paramétrique dePROTOCOLE* CONFORMANCE *. C'est-à-dire, pour rendre un NSMutableArray qui exige que tous les objets qui y sont placés soient conformes à un protocole donné (c'est-à-dire qu'ils disposent d'un ensemble donné de méthodes requises). 

Parfois, même cette vérification plus souple de la conformité de protocole est contrecarrée par les responsables de la programmation dynamique, et ce pour de bonnes raisons. Les programmeurs ont souvent le moyen de sur-spécifier les exigences de conformité. 

Par exemple, vous pourriez avoir besoin d'une liste contenant des objets conformes au protocole/à l'interface NSArray, mais vous pourriez aussiEN FAITappeler seulement deux de ces méthodes. C'est une surconformité. Quelqu'un qui souhaite coller un élément compatible dans votre tableau est obligé d'implémenter une tonne de méthodes que vous n'appelez pas réellement - du moins pas encore (voir ci-dessous).

Google Go tente de résoudre ce problème en déduisant une compatibilité structurelle. En d’autres termes, si vous appelez draw () sur des éléments sortant d’une liste, le compilateur s’assure que tout le contenu d’une liste contient une méthode draw (). S'il ne contient pas de méthode draw (), le compiler dans la liste est une erreur. Cela empêche le code de simplement provoquer la même erreur au moment de l'exécution. Le problème, c'est que cela ne fonctionne que pour la compilation de programmes complets. Si Google-Go pouvait compiler des DLL modulaires (ce qu'il ne pouvait pas), le problème serait qu'il ne m'est pas possible de dire que les objets de la liste doivent prendre en charge une interface spécifique de trois méthodes, même si Je ne les appelle pas aujourd'hui, car je pourrais les appeler à l'avenir

Entre ces deux solutions aime le compromis et la vérité.

Personnellement, j'aimerais que Objective-C ajoute la conformité de protocole paramétrique afin de pouvoir demander au compilateur de s'assurer que le contenu d'une collection particulière est toujours conforme à un ensemble de protocoles donné. 

J'aimerais aussi que le compilateur m'aide à éviter les conformités excessives. Si je n’appelle pas de méthodes dans ces protocoles sur des objets, cela devrait générer des erreurs/avertissements me le signalant. Si je veux les conserver dans le protocole même si je ne les utilise pas, je devrais explicitement déclarer, pour chaque méthode du protocole, que celle-ci "pourrait être utilisée à l'avenir, de sorte que tous les éléments doivent la fournir maintenant ". Cela oblige au moins le processus de surconformité à nécessiter PLUS de travail, au lieu de Java/C # où il nécessite moins de travail.

0
David Jeske