从什么时候开始在类别中声明Objective-C 2.0属性?

mak*_*dad 14 properties objective-c categories

我一直认为不能在类别中声明对象属性.直到我的合作伙伴在我们的应用程序代码中完成它,它似乎工作.

我继续SO和谷歌狂热试图向他解释不,Objective-C类别只能用于添加方法,而不是属性.我发现了诸如以下问题:

但后来我在Apple的网站上发现了这个链接,其中包含有关@property声明的以下内容:

属性声明以关键字@property开头.@property可以出现在类的@interface中找到的方法声明列表中的任何位置.@property 也可以出现在协议或类别的声明中.(重点补充)

我知道这不起作用:

@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
Run Code Online (Sandbox Code Playgroud)

但这编译:

@interface MyClass ()
@property NSInteger foobar;
- (void) someCategorizedMethod;
@end
Run Code Online (Sandbox Code Playgroud)

我的问题是(a)这里的最佳做法是什么?(b)这是Objective-C 2.0的新功能,而不是使用"真正的"iVar,它只是在幕后使用关联存储来实现这个功能吗?

bbu*_*bum 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
Run Code Online (Sandbox Code Playgroud)

它只是在幕后使用关联存储来完成这项工作?

不 - 它是一个真实的实例变量.现代运行时修复了脆弱的基类问题.


@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
Run Code Online (Sandbox Code Playgroud)

上述方法不起作用(如预期的那样),因为foobar它实际上是一个全局变量.

如果您将其更改为:

@interface MyClass () {
    NSInteger foobar;
}
- (void) someCategorizedMethod;
@end
Run Code Online (Sandbox Code Playgroud)

然后它将使用最新版本的llvm编译器(带有正确的标志,如@Joshua在评论中指出的那样).