隐藏公共访问的属性

lhu*_*ath 24 objective-c

我正在尝试声明仅供Private类别内部使用的属性:

@interface BarLayer (Private)

@property (readwrite, retain) MenuItemFont  *menuButton;
@property (readwrite, retain) Menu          *menuMenu;
@property (readwrite, retain) LabelAtlas    *messageLabel;

@end
Run Code Online (Sandbox Code Playgroud)

现在我想弄清楚我应该在哪里@synthesize.

我试过了:

@implementation BarLayer (Private)

@synthesize menuButton      = _menuButton;
@synthesize menuMenu        = _menuMenu;
@synthesize messageLabel    = _messageLabel;

@end
Run Code Online (Sandbox Code Playgroud)

在这里,编译器抱怨:

@synthesize不允许在类别的实现中

所以我尝试将它放在我的BarLayer实现中,但是在这里它没有在BarLayer界面中找到声明.

在界面中找不到属性'menuButton'的声明

正确的方法是什么?

Jes*_*sak 42

您不能使用@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
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是使用objc_setAssociatedObjectobjc_getAssociatedObject伪造其他实例变量.在这种情况下,您可以将这些声明为属性,并使用上面的objc_*运行时方法自己实现setter和getter.有关这些函数的更多详细信息,请参阅Objective-C运行时的Apple文档.


Ros*_*one 12

我找到了为什么在类别中禁止合成属性的解释,但是如何使用类扩展代替:

以下信息来自http://www.friday.com/bbum/2009/09/11/class-extensions-explained/

"合成在类别中被禁止的原因是因为合成需要存储,并且没有办法在一个类别中有效地声明存储,并且允许类别合成方法然后直接干掉类别的ivars被认为是不可接受的.太脆弱了而且丑陋.

但是,显然还希望能够声明一个公开只读的属性,但其实现是为了内部到类或框架目的而读写的.

另外一个要求是合成这些特性必须始终能够自然而精确地合成定位器和吸气剂.具体来说,当声明属性为原子时,开发人员无法正确地手动写入1/2的getter setter对; 锁定基础设施没有暴露,因此,在这种情况下无法保证原子性.

类扩展优雅地解决了这个问题.

具体来说,您可以声明一个属性,如:

@interface MyClass : NSObject
@property(readonly) NSView *targetView;
@end
Run Code Online (Sandbox Code Playgroud)

然后,在实现文件中:

@interface MyClass()
@property(readwrite) NSView *targetView;
@end

@implementation MyClass
@synthesize targetView;
@end
Run Code Online (Sandbox Code Playgroud)

最终结果?这是一种公开读取的属性,但私密地可以在不打开属性的情况下进行读写,直到与类别相关的所有有趣脆弱性."


f3l*_*lix 8

Scott Stevenson(http://theocacao.com/)在他的博客文章"A Quick Objective-C 2.0 Tutorial:Part II"中解释了如何使用Private Setters获取公共属性.根据他的建议,您将获得一个只读给公众的属性,但有一个私有的setter可以使用dot-syntax.希望这可以帮助...


lhu*_*ath 1

实际上,使用最新的LLVM编译器,这个问题可以得到更好的解决。之前推荐的尽可能隐藏属性的方法是在 .h 中声明变量,以 _ 为前缀,在私有 .m 中的类扩展中声明属性,然后在 @ 中 @synthesise 该属性。执行。

借助最新的 LLVM (3.0),您可以走得更远,隐藏有关您的财产的所有内容,包括支持 ivar。它的声明可以移动到 .m 甚至可以省略,在这种情况下它将由编译器合成(感谢 Ivan):

汽车.h:

@interface Car : NSObject

- (void)drive;

@end
Run Code Online (Sandbox Code Playgroud)

汽车.m:

@interface Car ()

@property (assign) BOOL driving;

@end

@implementation Car
@synthesize driving;

- (void)drive {

    self.driving = YES;
}

@end
Run Code Online (Sandbox Code Playgroud)