Die Möglichkeit, Instanzvariablen in den @implementationBlock oder in eine Klassenerweiterung einzufügen, ist eine Funktion der „modernen Objective-C-Laufzeit“, die von jeder iOS-Version und von 64-Bit-Mac OS X-Programmen verwendet wird.
Wenn Sie 32-Bit-Mac OS X-Apps schreiben möchten, müssen Sie Ihre Instanzvariablen in die @interfaceDeklaration einfügen. Möglicherweise müssen Sie jedoch keine 32-Bit-Version Ihrer App unterstützen. OS X unterstützt seit Version 10.5 (Leopard), die vor über fünf Jahren veröffentlicht wurde, 64-Bit-Apps.
Nehmen wir also an, Sie schreiben nur Apps, die die moderne Laufzeit verwenden. Wo solltest du deine Ivars hinstellen?
Option 0: In der @interface(Don't Do It)
Lassen Sie uns zunächst untersuchen, warum wir keine Instanzvariablen in eine @interfaceDeklaration einfügen möchten .
Durch das Einfügen von Instanzvariablen in wird @interfaceden Benutzern der Klasse Details der Implementierung angezeigt. Dies kann dazu führen, dass sich diese Benutzer (auch Sie selbst, wenn Sie Ihre eigenen Klassen verwenden!) Auf Implementierungsdetails verlassen, die sie nicht sollten. (Dies ist unabhängig davon, ob wir die Ivare deklarieren @private.)
Wenn Sie Instanzvariablen in eine Datei @interfaceeinfügen, dauert das Kompilieren länger, da wir jedes Mal, wenn wir eine ivar-Deklaration hinzufügen, ändern oder entfernen, jede .mDatei neu kompilieren müssen , die die Schnittstelle importiert.
Wir wollen also keine Instanzvariablen in die @interface. Wo sollen wir sie hinstellen?
Option 2: In den @implementationohne Klammern (Don't Do It)
Lassen Sie uns als Nächstes Ihre Option 2 diskutieren: "Setzen Sie iVars unter @implementantion ohne Block geschweifter Klammern". Dies deklariert keine Instanzvariablen! Sie sprechen darüber:
@implementation Person
int age;
NSString *name;
...
Dieser Code definiert zwei globale Variablen. Es werden keine Instanzvariablen deklariert.
Es ist in Ordnung, globale Variablen in Ihrer .mDatei zu definieren , auch in Ihrer @implementation, wenn Sie globale Variablen benötigen - zum Beispiel, weil alle Ihre Instanzen einen bestimmten Status haben sollen, z. B. einen Cache. Sie können diese Option jedoch nicht zum Deklarieren von Ivars verwenden, da Ivars nicht deklariert werden. (Außerdem sollten globale Variablen, die für Ihre Implementierung privat sind, normalerweise deklariert werden static, um eine Verschmutzung des globalen Namespace und das Risiko von Verbindungszeitfehlern zu vermeiden.)
Damit bleiben Ihre Optionen 1 und 3.
Option 1: In den @implementationmit Klammern (Do It)
Normalerweise möchten wir Option 1 verwenden: Setzen Sie sie @implementationin geschweiften Klammern wie folgt in Ihren Hauptblock:
@implementation Person {
int age;
NSString *name;
}
Wir setzen sie hier ein, weil es ihre Existenz privat hält und die zuvor beschriebenen Probleme verhindert, und weil es normalerweise keinen Grund gibt, sie in eine Klassenerweiterung aufzunehmen.
Wann möchten wir Ihre Option 3 verwenden und sie in eine Klassenerweiterung einfügen?
Option 3: In einer Klassenerweiterung (nur bei Bedarf ausführen)
Es gibt fast nie einen Grund, sie in einer Klassenerweiterung in derselben Datei wie die Klasse abzulegen @implementation. Wir könnten sie @implementationin diesem Fall genauso gut in den Fall setzen.
Gelegentlich schreiben wir jedoch eine Klasse, die groß genug ist, um den Quellcode in mehrere Dateien aufzuteilen. Wir können das mit Kategorien machen. Wenn wir beispielsweise implementieren UICollectionView(eine ziemlich große Klasse), könnten wir entscheiden, dass wir den Code, der die Warteschlangen wiederverwendbarer Ansichten (Zellen und zusätzliche Ansichten) verwaltet, in eine separate Quelldatei einfügen möchten. Wir könnten das tun, indem wir diese Nachrichten in eine Kategorie aufteilen:
@interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
@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, jetzt können wir die UICollectionViewHauptmethoden in UICollectionView.mimplementieren und die Methoden implementieren UICollectionView+ReusableViews.m, mit denen wiederverwendbare Ansichten verwaltet werden , wodurch unser Quellcode ein wenig übersichtlicher wird.
Unser wiederverwendbarer Ansichtsverwaltungscode benötigt jedoch einige Instanzvariablen. Diese Variablen müssen für die Hauptklasse @implementationin UICollectionView.mverfügbar gemacht werden, damit der Compiler sie in der .oDatei ausgibt. Außerdem müssen wir diese Instanzvariablen für den Code in verfügbar machen UICollectionView+ReusableViews.m, damit diese Methoden die ivars verwenden können.
Hier brauchen wir eine Klassenerweiterung. Wir können die ivars für die Verwaltung wiederverwendbarer Ansichten in eine Klassenerweiterung in einer privaten Header-Datei einfügen:
@interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
@end
Wir werden diese Header-Datei nicht an Benutzer unserer Bibliothek senden. Wir importieren nur in UICollectionView.mund in UICollectionView+ReusableViews.m, so dass alles, was Bedürfnisse diese ivars zu sehen , sie sehen. Wir haben auch eine Methode eingeführt, die die Hauptmethode initaufrufen soll, um den Code für die Verwaltung wiederverwendbarer Ansichten zu initialisieren. Wir werden diese Methode von -[UICollectionView initWithFrame:collectionViewLayout:]in aufrufen UICollectionView.mund in implementieren UICollectionView+ReusableViews.m.