Since when is it possible to declare Objective-C 2.0 properties in a category?

我是研究僧i 提交于 2019-12-03 17:12:44

问题


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:

  • 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:

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)

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?


回答1:


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.

However....

@interface MyClass () is not a category. It is a class extension and has a distinctly more specific role than a category.

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).

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.

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).




回答2:


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.

Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.

The main point here is that declaration of the ivar is independent from the property.




回答3:


Assotiative storage is the solution. Have a look at this post.



来源:https://stackoverflow.com/questions/4540149/since-when-is-it-possible-to-declare-objective-c-2-0-properties-in-a-category

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!