La possibilité de placer des variables d'instance dans le @implementation
ou dans une extension de classe, est une fonctionnalité du "runtime Objective-C moderne", qui est utilisé par toutes les versions d'iOS et par les programmes Mac OS X 64 bits.
Si vous voulez écrire des applications Mac OS X 32 bits, vous devez placer vos variables d'instance dans le fichier @interface
déclaration. Il est probable que vous n'ayez pas besoin de prendre en charge une version 32 bits de votre application. OS X prend en charge les applications 64 bits depuis la version 10.5 (Leopard), qui est sortie il y a plus de cinq ans.
Supposons donc que vous n'écriviez que des applications qui utiliseront le runtime moderne. Où devez-vous placer vos ivars ?
Option 0 : Dans le @interface
(Ne le faites pas)
D'abord, voyons pourquoi nous Ne le fais pas. vous voulez mettre des variables d'instance dans un @interface
déclaration.
-
Placer des variables d'instance dans un @interface
expose les détails de l'implémentation aux utilisateurs de la classe. Cela peut conduire ces utilisateurs (même vous-même lorsque vous utilisez vos propres classes !) à se fier à des détails d'implémentation qu'ils ne devraient pas. (Ceci est indépendant du fait que nous déclarions ou non les ivars @private
.)
-
Placer des variables d'instance dans un @interface
rend la compilation plus longue, car chaque fois que nous ajoutons, modifions ou supprimons une déclaration ivar, nous devons recompiler toutes les déclarations ivar. .m
qui importe l'interface.
Donc, nous ne voulons pas mettre les variables d'instance dans la section @interface
. Où devons-nous les mettre ?
Option 2 : Dans le @implementation
sans appareil dentaire (Ne le faites pas)
Ensuite, discutons de votre option 2, "Mettre les iVars sous @implementantion sans bloc d'accolades". Cette option fait pas déclarer les variables d'instance ! Vous parlez de cela :
@implementation Person
int age;
NSString *name;
...
Ce code définit deux variables globales. Il ne déclare aucune variable d'instance.
Il n'y a pas de problème à définir des variables globales dans vos .m
même dans votre @implementation
si vous avez besoin de variables globales - par exemple, parce que vous voulez que toutes vos instances partagent un certain état, comme un cache. Mais vous ne pouvez pas utiliser cette option pour déclarer des ivars, car elle ne les déclare pas. (De plus, les variables globales privées à votre implémentation devraient généralement être déclarées comme suit static
pour éviter de polluer l'espace de noms global et risquer des erreurs au moment de la liaison).
Il vous reste donc les options 1 et 3.
Option 1 : Dans le @implementation
avec un appareil dentaire (Do It)
En général, il est préférable d'utiliser l'option 1 : les placer dans votre dossier principal. @implementation
entre accolades, comme ceci :
@implementation Person {
int age;
NSString *name;
}
Nous les plaçons ici parce que leur existence reste privée, ce qui évite les problèmes que j'ai décrits précédemment, et parce qu'il n'y a généralement aucune raison de les placer dans une extension de classe.
Alors quand voulons-nous utiliser votre option 3, les mettre dans une extension de classe ?
Option 3 : Dans une extension de classe (à ne faire qu'en cas de nécessité)
Il n'y a presque jamais de raison de les placer dans une extension de classe, dans le même fichier que le fichier de la classe. @implementation
. Nous pourrions tout aussi bien les mettre dans le @implementation
dans ce cas.
Mais de temps en temps, nous pouvons écrire une classe qui est assez grande pour que nous voulions diviser son code source en plusieurs fichiers. Nous pouvons le faire en utilisant des catégories. Par exemple, si nous implémentons UICollectionView
(une classe assez grande), nous pourrions décider de mettre le code qui gère les files d'attente des vues réutilisables (cellules et vues supplémentaires) dans un fichier source séparé. Nous pourrions le faire en séparant ces messages dans une catégorie :
// UICollectionView.h
@interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.
@end
@interface UICollectionView (ReusableViews)
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
@end
OK, maintenant nous pouvons implémenter l'élément principal UICollectionView
méthodes en UICollectionView.m
et nous pouvons implémenter les méthodes qui gèrent les vues réutilisables en UICollectionView+ReusableViews.m
ce qui rend notre code source un peu plus facile à gérer.
Mais notre code de gestion des vues réutilisables a besoin de quelques variables d'instance. Ces variables doivent être exposées à la classe principale @implementation
en UICollectionView.m
de sorte que le compilateur les émettra dans le fichier .o
fichier. Et nous avons également besoin d'exposer ces variables d'instance au code en UICollectionView+ReusableViews.m
pour que ces méthodes puissent utiliser les ivars.
C'est là que nous avons besoin d'une extension de classe. Nous pouvons mettre les ivars reusable-view-management dans une extension de classe dans un fichier d'en-tête privé :
// UICollectionView_ReusableViewsSupport.h
@interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
@end
Nous n'allons pas envoyer ce fichier d'en-tête aux utilisateurs de notre bibliothèque. Nous l'importerons simplement dans UICollectionView.m
et en UICollectionView+ReusableViews.m
de sorte que tout ce qui besoins pour voir ces ivars peuvent les voir. On a aussi ajouté une méthode pour que le programme principal init
à appeler pour initialiser le code de gestion des vues réutilisables. Nous appellerons cette méthode à partir de -[UICollectionView initWithFrame:collectionViewLayout:]
en UICollectionView.m
et nous l'implémenterons dans UICollectionView+ReusableViews.m
.