La réponse donnée fonctionne très bien et ma proposition n'est qu'une extension de celle-ci qui évite d'écrire trop de code standard.
Afin d'éviter d'écrire à plusieurs reprises des méthodes getter et setter pour les propriétés de catégorie, cette réponse introduit des macros. De plus, ces macros facilitent l'utilisation de propriétés de type primitif telles que int
ou BOOL
.
Approche traditionnelle sans macros
Traditionnellement, vous définissez une propriété de catégorie comme
@interface MyClass (Category)
@property (strong, nonatomic) NSString *text;
@end
Ensuite, vous devez implémenter une méthode getter et setter en utilisant un objet associé et le sélecteur get comme clé ( voir la réponse d'origine ):
#import <objc/runtime.h>
@implementation MyClass (Category)
- (NSString *)text{
return objc_getAssociatedObject(self, @selector(text));
}
- (void)setText:(NSString *)text{
objc_setAssociatedObject(self, @selector(text), text, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
Mon approche suggérée
Maintenant, en utilisant une macro, vous allez écrire à la place:
@implementation MyClass (Category)
CATEGORY_PROPERTY_GET_SET(NSString*, text, setText:)
@end
Les macros sont définies comme suit:
#import <objc/runtime.h>
#define CATEGORY_PROPERTY_GET(type, property) - (type) property { return objc_getAssociatedObject(self, @selector(property)); }
#define CATEGORY_PROPERTY_SET(type, property, setter) - (void) setter (type) property { objc_setAssociatedObject(self, @selector(property), property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
#define CATEGORY_PROPERTY_GET_SET(type, property, setter) CATEGORY_PROPERTY_GET(type, property) CATEGORY_PROPERTY_SET(type, property, setter)
#define CATEGORY_PROPERTY_GET_NSNUMBER_PRIMITIVE(type, property, valueSelector) - (type) property { return [objc_getAssociatedObject(self, @selector(property)) valueSelector]; }
#define CATEGORY_PROPERTY_SET_NSNUMBER_PRIMITIVE(type, property, setter, numberSelector) - (void) setter (type) property { objc_setAssociatedObject(self, @selector(property), [NSNumber numberSelector: property], OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
#define CATEGORY_PROPERTY_GET_UINT(property) CATEGORY_PROPERTY_GET_NSNUMBER_PRIMITIVE(unsigned int, property, unsignedIntValue)
#define CATEGORY_PROPERTY_SET_UINT(property, setter) CATEGORY_PROPERTY_SET_NSNUMBER_PRIMITIVE(unsigned int, property, setter, numberWithUnsignedInt)
#define CATEGORY_PROPERTY_GET_SET_UINT(property, setter) CATEGORY_PROPERTY_GET_UINT(property) CATEGORY_PROPERTY_SET_UINT(property, setter)
La macro CATEGORY_PROPERTY_GET_SET
ajoute un getter et un setter pour la propriété donnée. Les propriétés en lecture seule ou en écriture seule utiliseront respectivement la macro CATEGORY_PROPERTY_GET
et CATEGORY_PROPERTY_SET
.
Les types primitifs ont besoin d'un peu plus d'attention
Comme les types primitifs ne sont pas des objets, les macros ci-dessus contiennent un exemple à utiliser unsigned int
comme type de propriété. Il le fait en enveloppant la valeur entière dans un NSNumber
objet. Son utilisation est donc analogue à l'exemple précédent:
@interface ...
@property unsigned int value;
@end
@implementation ...
CATEGORY_PROPERTY_GET_SET_UINT(value, setValue:)
@end
Suivant ce modèle, vous pouvez simplement ajouter des macros pour soutenir aussi signed int
, BOOL
, etc ...
Limites
Toutes les macros utilisent OBJC_ASSOCIATION_RETAIN_NONATOMIC
par défaut.
Les IDE comme App Code ne reconnaissent actuellement pas le nom du setter lors de la refactorisation du nom de la propriété. Vous devrez le renommer vous-même.