在所谓的“Modern Objective-C”之前,当在类别中创建新属性时,我们需要实现setter和getter方法。现在,我们不必做@synthesize
;编译器将自动创建方法和实例变量。
但通常情况下,我们无法将实例变量添加到类别中,那么如果我们在具有现代Objective-C的类别中添加新属性会发生什么?编译器是否为我们创建了一个ivar?
答案 0 :(得分:6)
您可以在类别中声明属性,这相当于声明getter和(如果是readwrite)setter选择器。
编译器将不自动合成类别实现中的getter和setter方法。如果未在类别实现中明确定义它们,编译器将发出警告。您可以在类别实现中使用@dynamic
来禁止警告。您不能在类别实现中使用@synthesize
;如果你尝试,编译器会发出错误。
编译器不会为类别中声明的属性添加实例变量。您无法在类别中显式添加实例变量,也无法欺骗编译器使用属性执行此操作。
我使用针对iOS 6.0的Xcode 4.5.1测试了我的声明。
答案 1 :(得分:1)
实际上我不知道我们什么时候可以在类别中添加property
。
来自Apple Docs:
类别允许您将方法添加到现有类 - 甚至是您没有源的类。
和
类扩展类似于匿名类别,除了它们声明的方法必须在相应类的主@implementation块中实现。使用Clang / LLVM 2.0编译器,您还可以在类扩展中声明属性和实例变量。
此方法用于将存储添加到对象而不修改类声明(如果您无法修改或无法访问源代码)班级)
从OS X v10.6开始提供的关联引用模拟对象实例变量添加到现有类。使用关联引用,可以在不修改类声明的情况下向对象添加存储。 如果您无法访问该类的源代码,或者由于二进制兼容性原因您无法更改该对象的布局,则此选项可能很有用。
所以你的问题似乎不正确。
答案 2 :(得分:0)
正如其他人所说,实现此目的的方法是使用 关联引用 。它们实现非常类似于 CALayer
的价值/密钥对范式......基本上......你可以“关联”任何东西,任何“财产”或“东西”......
所以在你的类别标题中......如果你想做的只是读取一个值......
@property(readonly)NSString * uniqueID;
然后写下你的getter ......
- (NSString*) uniqueID { return @"You're not special"; }
但是说...你不能只是从你的getter中得到的价值......你需要存储外部的setter ......或者类的自己的实现才能使用......你必须写一个类似的setter。 ..
- (void) setUniqueID:(NSString*)uId
它不一定是公开的,必然......但这就是“神奇”发生的地方。
…
[self setAssociatedValue:uId forKey:@"yourInternalStorageName"
policy:OBJC_ASSOCIATION_RETAIN_NONATOMIC];
我在看了这个之后意识到,我正在使用一些“个人类别”来帮助简化这些值的设置和获取等等。所以I've posted them to this gist,因为它们非常有用..并且包括像...这样的小宝石。
- (id) associatedValueForKey:(NSString*)key
orSetTo:(id)anObject
policy:(objc_AssociationPolicy) policy;
“得到它”的秘诀是“政策”部分......这些价值......
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
捕获与在“正常”声明中描述属性时表达的相同“个性”特征。您必须告诉编译器如何使用相同的规则“存储”您的值,并且您将会很高兴。