在创建一个objc对象时,alloc负责分配内存,init负责对对象进行初始化。也就是说,init其实就是其他语言中的构造函数。
但是如果需要在构造函数中调用父类与子类同名的对象方法时,objc和C++两种语言输出的结果却截然不同。
先看C++:
#include <iostream>
using namespace std;
class A{
public:
A(){
log();
};
void log(){
cout<< "A:";
cout<< this <<endl;
}
};
class B:public A{
public:
B(){
log();
}
void log(){
cout<< "B:";
cout<< this <<endl;
}
};
int main(int argc, const char * argv[]) {
B *b = new B;
delete b;
return 0;
}
输出结果为:
A:0x100200540
B:0x100200540
可见调用顺序为: 父类构造函数->基类同名方法->子类构造函数->子类同名方法。
再看objc:
#import <Foundation/Foundation.h>
@interface A : NSObject
@end
@implementation A
- (instancetype)init
{
if (self = [super init]) {
[self log];
}
return self;
}
- (void)log
{
NSLog(@"A: %@",self);
}
@end
@interface B : A
@end
@implementation B
- (instancetype)init
{
if (self = [super init]) {
[self log];
}
return self;
}
- (void)log
{
NSLog(@"B: %@",self);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
B *b = [[B alloc]init];
}
return 0;
}
执行结果为:
ocinit[29764:9300639] B: <B: 0x100300480>
ocinit[29764:9300639] B: <B: 0x100300480>
通过断点,确认执行顺序为: 父类构造函数->子类同名方法->子类构造函数->子类同名方法。
原因猜测:
C++中对象的内存布局中会保存当前对象所有函数的地址,调用时会首先在本类的内存布局中查找要调用的函数,若未找到,则会在父类中继续查找。 所以父类的构造函数中调用的是自身的同名方法。
而objc的实例对象(instacne objec)中都有一个isa指针,指向它的类对象(class object),类对象(class object)中存储了关于这个实例对象(instace object)所属的类的定义的一切:包括变量,方法,遵守的协议等等。 在进行alloc操作时,就进行了isa指针的初始化,所以在父类的构造方法中调用的其实也是子类类对象中储存的方法, 即子类的同名方法。