关于ObjC的private method,一直不太确定其规则,故用程序测试一下。
定义三个类,MyClass, MySubClass, MyOtherClass. 其中MySubClass继承自MyClass, MyOtherClass独立存在。
关于private method有两种说法,一说使用category来实现,即在.m文件中如下书写,
@interface MyClass()
- (void)privateMethod;
@end
另一说法是直接在@implement里书写函数,而不在.h中定义即可达到private目的,即
@implement MyClass
- (void)privateMethod {
NSLog(@"privateMethod called");
}
@end
究竟这两种方法有没有不同?private究竟有多private?请往下看。
首先,我把MyClass, MySubClass, MyOtherClass以及test driver分别放在不同的.m文件中,一个4个文件,结果是
1. 在test driver中生成三个instance,
MyClass* myObj;
MySubClass* mySubObj;
MyOtherClass* myOtherObj;
对myObj调用privateMethod, 即
[myObj privateMethod];
结果,编译出错。OK, 和传统的private行为一致。
2. 使用NSObject的performSelector调用privateMethod,即,
[myObj performSelector:@selector(privateMethod)];
[mySubObj performSelector:@selector(privateMethod)];
结果,编译通过(必然的),调用成功——console上印出privateMethod called。
接下来,将MyClass, MySubClass, MyOtherClass全部放在一个.m中实现,加上test driver,一个2个文件,结果是,
1. 还是在test driver中生成三个instance, 对myObj调用privateMethod, 即
[myObj privateMethod];
结果,编译仍然出错。OK,没有疑问。(不论是使用category方式还是直接书写方式实现private都一样)
2. 在MySubClass中加入public方法,并在其中调用父类MyClass的privateMethod,如下,
-(void)printSubClass {
[self privateMethod];
}
然后在test driver中调用MySubClass的printSubClass method,即
[mySubObj printSubClass];
结果,编译通过!调用正常!(不论是使用category方式还是直接书写方式实现private都一样)
3. 测试2已经让我看到一些眉目,接下来再夸张一点,在MyOtherClass中中加入public方法,生成一个MyClass的instance,并调用privateMethod,即
-(void)printMyOtherClass {
MyClass* myObj = [[MyClass alloc] init];
[myObj privateMethod];
}
然后在test driver中调用MyOtherClass的printMyOtherClass method,即
[myOtherObj printMyOtherClass];
结果,编译仍然通过!调用仍然正常!
根据以上结果,大胆猜测,
1. 和继承不一样,ObjC所谓的private method只是文件作用域的问题,只要在同一文件中,就可以访问到,并没有在object system中维护这样一个标志
2. 结论1仅对于method call方式有意义,即[obj method]方式有文件作用域问题
3. 因为ObjC根本没有语言级的private method,所以performSelector可以call到类里的所有method
4. method call方式有文件作用域问题,可见method call仍然是编译时binding的,为了效率?performSelector则是完全的dynamic-binding
5. 使用category方式和直接书写方式实现private效果是一样的
肤浮理解,欢迎斧正!
P.S: 后话,找到一篇比较权威的资料,里面写到,
Methods can only be public. However, it is possible to mimic the private mode, by implementing some methods in the @implementation, without declaring them in the @interface, or using the notion of class category.