我一直认为不能在类别中声明对象属性。 直到我的合作伙伴在我们的应用程序代码中完成它,它似乎工作。
我继续进行SO和谷歌狂欢试图向他解释不,Objective-C类别只能用于添加方法,而不能用于添加属性。我找到了诸如以下的问题:
但后来我在Apple的网站上找到了this link,其中包含有关@property声明的以下内容:
属性声明以。开头 关键字@property。 @property可以 出现在方法的任何地方 声明清单在 @interface的一个类。 @property 可以 也出现在宣言中 协议或类别。 (重点补充)
我知道这不起作用:
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
但这会编译:
@interface MyClass ()
@property NSInteger foobar;
- (void) someCategorizedMethod;
@end
我的问题是(a)这里的最佳做法是什么? (b)这是Objective-C 2.0的新功能,而不是使用“真正的”iVar,它只是在幕后使用关联存储来实现这个功能吗?
答案 0 :(得分:31)
您始终可以在某个类别中声明@property
。你不能做的 - 现在仍然不能 - 为类别中的属性声明存储,既不作为实例变量也不通过`@synthesize。
然而....
@interface MyClass ()
不是类别。它是一个类扩展,具有明显比类别更具体的角色。
即,类扩展可以用于扩展类的@interface ,这包括可以@synthesized的@properties(包括在现代运行时中合成存储)。
Foo.h:
@interface Foo
@end
Foo.m:
@interface Foo()
@property int x;
@end
@implementation Foo
@synthesize x; // synthesizes methods & storage
@end
它只是使用关联存储 在幕后做这项工作?
不 - 它是一个真正的实例变量。现代运行时修复了脆弱的基类问题。
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
上述方法不起作用(如预期的那样),因为foobar
实际上是一个全局变量。
如果您将其更改为:
@interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
@end
然后它将与最新版本的llvm编译器一起使用(带有正确的标志,如@Joshua在评论中指出的那样)。
答案 1 :(得分:1)
一般来说,属性与其他方法没有什么不同。只要使用的ivar在普通类中可用,就没有任何问题。这只是语法糖。
如果自动创建了ivar,事情开始变得更加困难,就像在一些配置中一样。
这里的要点是伊娃的声明独立于财产。
答案 2 :(得分:1)
Assotiative storage是解决方案。 看看这个post。