@public、@protected 和 @private 指令是
在 Objective-C 中没有绑定,它们是关于编译器的提示
变量的可访问性。
它不会限制您访问它们。
示例:
@interface Example : Object
{
@public
int x;
@private
int y;
}
...
...
id ex = [[Example alloc ] init];
ex->x = 10;
ex->y = -10;
printf(" x = %d , y = %d \n", ex->x , ex->y );
...
gcc 编译器吐出来:
Main.m:56:1: 警告:实例变量‘y’是@private;这将是未来的一个硬错误
Main.m:57:1: 警告:实例变量‘y’是@private;这将是未来的一个硬错误
对“private”成员y的每个“不适当”访问一次,但无论如何都会编译它。
运行时得到
x = 10 , y = -10
所以你真的不能用这种方式编写访问代码,而是因为 objc 是 C 的 超集,
C 语法工作得很好,所有的类都是透明的。
您可以将编译器设置为将这些警告视为错误并放弃——但 Objective-C 内部并未针对这种严格性进行设置。动态方法分派必须检查每个调用的范围和权限 (slooooowwwww...),因此除了编译时警告之外,系统还希望程序员尊重数据成员范围。
在 Objective-C 中获取成员隐私有几个技巧。
一种是确保将类的接口和实现分别放在单独的 .h 和 .m 文件中,并将数据成员放在实现文件(.m 文件)中。
然后导入标头的文件无法访问数据成员,只能访问类本身。
然后在标题中提供访问方法(或不)。您可以实现 setter/getter 函数
如果需要,在实现文件中用于诊断目的,它们将是可调用的,
但不会直接访问数据成员。
示例:
@implementation Example2 :Object
{
//nothing here
}
double hidden_d; // hey now this isn't seen by other files.
id classdata; // neither is this.
-(id) classdata { return [classdata data]; } // public accessor
-(void) method2 { ... }
@end
// this is an "informal category" with no @interface section
// these methods are not "published" in the header but are valid for the class
@implementation Example2 (private)
-(void)set_hidden_d:(double)d { hidden_d = d; }
// You can only return by reference, not value, and the runtime sees (id) outside this file.
// You must cast to (double*) and de-reference it to use it outside of this file.
-(id) hidden_d_ptr { return &hidden_d;}
@end
...
[Main.m]
...
ex2 = [[Example2 alloc] init];
double d = ex2->hidden_d; // error: 'struct Example2’ has no member named ‘hidden_d’
id data = ex2->classdata; // error: 'struct Example2’ has no member named ‘classdata’
id data = [ex2 classdata] // OK
[ex2 set_hidden_d : 6.28318 ]; // warning:'Example2' may not respond to '-set_hidden_d:'
double* dp = [ex2 hidden_d_ptr]; // (SO UGLY) warning: initialization from incompatible pointer type
// use (double*)cast -- <pointer-to-pointer conversion>
double d = (*dp); // dereference pointer (also UGLY).
...
编译器会对这种公然的恶作剧发出警告,但会继续执行
并相信您知道自己在做什么(真的吗?),并且您有自己的理由(是吗?)。
看起来工作量很大?容易出错?耶宝贝!
在诉诸魔术 C 技巧和像这样的肉丸手术之前,请先尝试重构您的代码。
但确实如此。祝你好运。