我正在尝试声明仅供Private
类别内部使用的属性:
@interface BarLayer (Private) @property (readwrite, retain) MenuItemFont *menuButton; @property (readwrite, retain) Menu *menuMenu; @property (readwrite, retain) LabelAtlas *messageLabel; @end
现在我想弄清楚我应该在哪里@synthesize
.
我试过了:
@implementation BarLayer (Private) @synthesize menuButton = _menuButton; @synthesize menuMenu = _menuMenu; @synthesize messageLabel = _messageLabel; @end
在这里,编译器抱怨:
@synthesize不允许在类别的实现中
所以我尝试将它放在我的BarLayer
实现中,但是在这里它没有在BarLayer
界面中找到声明.
在界面中找不到属性'menuButton'的声明
正确的方法是什么?
您不能使用@synthesize
类别.
您可以使用类扩展(也称为匿名类别)来执行此操作,该类扩展只是一个没有名称的类别,其方法必须在@implementation
该类的主块中实现.对于您的代码,只需将"(Private)"更改为"()",并@synthesize
在主@implementation
块中使用该类的其余代码.
有关详细信息,请参阅有关扩展的Apple文档.(显然这是Mac OS 10.5中的新功能.)
编辑:一个例子:
// Main interface (in .h) @interface Foo : NSObject - (void)bar; @end // Private interface (in .m, or private .h) @interface Foo () @property (nonatomic, copy) NSString *myData; @end @implementation Foo @synthesize myData; // only needed for Xcode 4.3 and earlier - (void)bar { ... } @end
另一个解决方案是使用objc_setAssociatedObject
和objc_getAssociatedObject
伪造其他实例变量.在这种情况下,您可以将这些声明为属性,并使用上面的objc_*运行时方法自己实现setter和getter.有关这些函数的更多详细信息,请参阅Objective-C运行时的Apple文档.
我找到了为什么在类别中禁止合成属性的解释,但是如何使用类扩展代替:
以下信息来自http://www.friday.com/bbum/2009/09/11/class-extensions-explained/
"合成在类别中被禁止的原因是因为合成需要存储,并且没有办法在一个类别中有效地声明存储,并且允许类别合成方法然后直接干掉类别的ivars被认为是不可接受的.太脆弱了而且丑陋.
但是,显然还希望能够声明一个公开只读的属性,但其实现是为了内部到类或框架目的而读写的.
另外一个要求是合成这些特性必须始终能够自然而精确地合成定位器和吸气剂.具体来说,当声明属性为原子时,开发人员无法正确地手动写入1/2的getter setter对; 锁定基础设施没有暴露,因此,在这种情况下无法保证原子性.
类扩展优雅地解决了这个问题.
具体来说,您可以声明一个属性,如:
@interface MyClass : NSObject @property(readonly) NSView *targetView; @end
然后,在实现文件中:
@interface MyClass() @property(readwrite) NSView *targetView; @end @implementation MyClass @synthesize targetView; @end
最终结果?这是一种公开读取的属性,但私密地可以在不打开属性的情况下进行读写,直到与类别相关的所有有趣脆弱性."
Scott Stevenson(http://theocacao.com/)在他的博客文章"A Quick Objective-C 2.0 Tutorial:Part II"中解释了如何使用Private Setters获取公共属性.根据他的建议,您将获得一个只读给公众的属性,但有一个私有的setter可以使用dot-syntax.希望这可以帮助...