web-dev-qa-db-fra.com

Existe-t-il des collections fortement typées dans Objective-C?

Je suis nouveau dans la programmation Mac/iPhone et Objective-C. En C # et Java nous avons des "génériques", classes de collection dont les membres ne peuvent être que du type déclaré. Par exemple, en C #

Dictionary<int, MyCustomObject>

ne peut contenir que des clés qui sont des entiers et des valeurs de type MyCustomObject. Existe-t-il un mécanisme similaire dans Objective-C?

138
Rich

Dans Xcode 7, Apple a introduit les "génériques légers" dans Objective-C. Dans Objective-C, ils génèrent des avertissements pour le compilateur en cas d'incompatibilité de types.

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

Et dans le code Swift, ils produiront une erreur du compilateur:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

Les génériques légers sont destinés à être utilisés avec NSArray, NSDictionary et NSSet, mais vous pouvez également les ajouter à vos propres classes:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-C se comportera comme avant avec les avertissements du compilateur.

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

mais Swift ignorera complètement les informations génériques. (Plus vrai dans Swift 3+.)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

Outre les classes de la collection Foundation, les génériques légers Objective-C sont ignorés par Swift. Tous les autres types utilisant des génériques légers sont importés dans Swift) comme s'ils n'étaient pas paramétrés.

Interaction avec les API Objective-C

209
Connor

Cette réponse est obsolète mais reste pour la valeur historique. À partir de Xcode 7, la réponse de Connor du 8 juin 2015 est plus précise.


Non, Objective-C ne contient pas de génériques, sauf si vous souhaitez utiliser des modèles C++ dans vos propres classes de collection personnalisées (ce que je décourage vivement).

Objective-C a pour typage dynamique le typage dynamique, ce qui signifie que le moteur d'exécution ne se soucie pas du type d'un objet car tous les objets peuvent recevoir des messages. Lorsque vous ajoutez un objet à une collection intégrée, ils sont simplement traités comme s'ils étaient de type id. Mais ne vous inquiétez pas, envoyez simplement des messages à ces objets comme d'habitude; cela fonctionnera bien (à moins bien sûr qu'un ou plusieurs objets de la collection ne répondent pas au message que vous envoyez).

Les génériques sont nécessaires dans des langages tels que Java et C #, car ce sont des langages forts, typés statiquement. Ballgame totalement différent de la fonctionnalité de typage dynamique d'Objective-C.

91
Marc W

Non, mais pour que ce soit plus clair, vous pouvez le commenter avec le type d'objet que vous voulez stocker, je l'ai déjà vu faire quelques fois lorsque vous devez écrire quelque chose dans Java 1.4 de nos jours) par exemple:

NSMutableArray* /*<TypeA>*/ arrayName = ....

ou

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
11
Mark Rhodes

Il n'y a pas de génériques dans Objective-C.

à partir de la documentation

Les tableaux sont des collections ordonnées d'objets. Cocoa fournit plusieurs classes de tableaux, NSArray, NSMutableArray (une sous-classe de NSArray) et NSPointerArray.

6
Matthew Vines

Apple a ajouté des génériques à ObjC dans XCode 7:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

voir ici: https://developer.Apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//Apple_ref/doc/uid/TP400142- CH6-ID61

6
user1259710

Ceci a été publié dans Xcode 7 (enfin!)

Notez que dans le code Objective C, il ne s'agit que d'une vérification à la compilation; il n'y aura pas d'erreur d'exécution simplement pour avoir placé le mauvais type dans une collection ou assigné à une propriété typée.

Déclarer:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

Utilisation:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

Attention à ces *s.

5
Kevin

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.

Un exemple: List<int> pourrait être réalisé par une classe personnalisée appelée NumberArray, créée avec l’instruction suivante:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

Une fois que vous avez créé NumberArray, vous pouvez l’utiliser partout dans votre projet. Il manque la syntaxe de <int>, mais vous pouvez choisir votre propre schéma de nommage pour les étiqueter en tant que classes et modèles.

4
w-m

Maintenant, les rêves deviennent réalité - il y a des génériques dans Objective-C depuis aujourd'hui (merci, WWDC). Ce n'est pas une blague - sur page officielle de Swift:

Les nouvelles fonctionnalités de syntaxe vous permettent d'écrire du code plus expressif tout en améliorant la cohérence dans le langage. Les kits de développement logiciel ont utilisé les nouvelles fonctionnalités d'Objective-C, telles que les génériques et les annotations Nullable, pour rendre le code Swift encore plus propre et plus sûr. Voici un échantillon de Swift 2.0 améliorations.

Et une image qui le prouve:Objective-C generics

2
htzfun

Jeter un coup d'œil à:

https://github.com/tomersh/Objective-C-Generics

Cela semble être une sorte de générique de pauvre homme, en réutilisant le mécanisme de vérification de protocole.

2
David Jeske

Je veux juste sauter ici. J'ai écrit un article de blog ici à propos de Generics.

Ce que je veux contribuer, c’est que des génériques peuvent être ajoutés à n’importe quelle classe , pas seulement aux classes de collection telles que Apple indique.

J'ai ensuite ajouté avec succès diverses classes, car elles fonctionnent exactement comme les collections d'Apple. c'est à dire. compilation de la vérification du temps, la complétion du code, permettant l'enlèvement des moulages, etc.

Prendre plaisir.

2
drekka