I always thought that one cannot declare an object property in a category. Until my partner did it in our app's code, and it seemed to work.
我一直认为不能在类别中声明对象属性。直到我的合作伙伴在我们的应用程序代码中完成它,它似乎工作。
I went on a SO and Google binge to try to explain to him that no, Objective-C categories can only be used to add methods, not properties. I found questions such as:
我继续SO和谷歌*试图向他解释不,Objective-C类别只能用于添加方法,而不是属性。我发现了诸如以下问题:
- Setting New Property In Category Interface Implementation (look at the accepted answer)
- 在类别接口实现中设置新属性(查看接受的答案)
- Can I add a property for a method not in my category?
- 我可以为不属于我的类别的方法添加属性吗?
But then I found this link on Apple's site that contains the following about the @property declaration:
但后来我在Apple的网站上发现了这个链接,其中包含有关@property声明的以下内容:
A property declaration begins with the keyword @property. @property can appear anywhere in the method declaration list found in the @interface of a class. @property can also appear in the declaration of a protocol or category. (emphasis added)
属性声明以关键字@property开头。 @property可以出现在类的@interface中的方法声明列表中的任何位置。 @property也可以出现在协议或类别的声明中。 (重点补充)
I know that this doesn't work:
我知道这不起作用:
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
But this compiles:
但这编译:
@interface MyClass ()
@property NSInteger foobar;
- (void) someCategorizedMethod;
@end
My question is (a) what's the best practice here? and (b) is this something that is new to Objective-C 2.0, and instead of using a "real" iVar, it simply uses associative storage behind the scenes to make this work?
我的问题是(a)这里的最佳做法是什么? (b)这是Objective-C 2.0的新功能,而不是使用“真正的”iVar,它只是在幕后使用关联存储来实现这个功能吗?
3 个解决方案
#1
31
You have always been able to declare an @property
in a category. What you couldn't do -- and still can't -- is declare storage for the property in the category, neither as an instance variable nor via `@synthesize.
您始终可以在类别中声明@property。你不能做的 - 现在仍然不能 - 为类别中的属性声明存储,既不作为实例变量也不通过`@synthesize。
However....
然而....
@interface MyClass ()
is not a category. It is a class extension and has a distinctly more specific role than a category.
@interface MyClass()不是一个类别。它是一个类扩展,具有明显比类别更具体的角色。
Namely, a class extension can be used to extend a class's @interface, and this includes @properties that can be @synthesized (including synthesizing storage in the modern runtime).
也就是说,类扩展可用于扩展类的@interface,这包括可以@synthesized的@properties(包括在现代运行时中合成存储)。
Foo.h:
@interface Foo
@end
Foo.m:
@interface Foo()
@property int x;
@end
@implementation Foo
@synthesize x; // synthesizes methods & storage
@end
it simply uses associative storage behind the scenes to make this work?
它只是在幕后使用关联存储来实现这个目的吗?
Nope -- it is a real instance variable. The modern runtime fixes the fragile base class problem.
不 - 它是一个真正的实例变量。现代运行时修复了脆弱的基类问题。
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
The above doesn't work (as expected) because foobar
is, effectively, a global variable.
上述方法不起作用(如预期的那样),因为foobar实际上是一个全局变量。
If you change it to:
如果您将其更改为:
@interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
@end
Then it'll work with the latest release of the llvm compiler (with the right flags, as @Joshua indicated in a comment).
然后它将使用最新版本的llvm编译器(带有正确的标志,如@Joshua在评论中指出的那样)。
#2
1
Generally speaking, properties are nothing different from other methods. As long as the ivar used is available in the ordinary class, there is no problem at all. It's just syntactic sugar.
一般来说,属性与其他方法没有什么不同。只要普通类中使用的ivar,就没有任何问题。这只是语法糖。
Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.
如果自动创建ivar,事情开始变得更加困难,在某些配置中也是如此。
The main point here is that declaration of the ivar is independent from the property.
这里的要点是伊萨尔的声明独立于财产。
#3
#1
31
You have always been able to declare an @property
in a category. What you couldn't do -- and still can't -- is declare storage for the property in the category, neither as an instance variable nor via `@synthesize.
您始终可以在类别中声明@property。你不能做的 - 现在仍然不能 - 为类别中的属性声明存储,既不作为实例变量也不通过`@synthesize。
However....
然而....
@interface MyClass ()
is not a category. It is a class extension and has a distinctly more specific role than a category.
@interface MyClass()不是一个类别。它是一个类扩展,具有明显比类别更具体的角色。
Namely, a class extension can be used to extend a class's @interface, and this includes @properties that can be @synthesized (including synthesizing storage in the modern runtime).
也就是说,类扩展可用于扩展类的@interface,这包括可以@synthesized的@properties(包括在现代运行时中合成存储)。
Foo.h:
@interface Foo
@end
Foo.m:
@interface Foo()
@property int x;
@end
@implementation Foo
@synthesize x; // synthesizes methods & storage
@end
it simply uses associative storage behind the scenes to make this work?
它只是在幕后使用关联存储来实现这个目的吗?
Nope -- it is a real instance variable. The modern runtime fixes the fragile base class problem.
不 - 它是一个真正的实例变量。现代运行时修复了脆弱的基类问题。
@interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
@end
The above doesn't work (as expected) because foobar
is, effectively, a global variable.
上述方法不起作用(如预期的那样),因为foobar实际上是一个全局变量。
If you change it to:
如果您将其更改为:
@interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
@end
Then it'll work with the latest release of the llvm compiler (with the right flags, as @Joshua indicated in a comment).
然后它将使用最新版本的llvm编译器(带有正确的标志,如@Joshua在评论中指出的那样)。
#2
1
Generally speaking, properties are nothing different from other methods. As long as the ivar used is available in the ordinary class, there is no problem at all. It's just syntactic sugar.
一般来说,属性与其他方法没有什么不同。只要普通类中使用的ivar,就没有任何问题。这只是语法糖。
Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.
如果自动创建ivar,事情开始变得更加困难,在某些配置中也是如此。
The main point here is that declaration of the ivar is independent from the property.
这里的要点是伊萨尔的声明独立于财产。