- 為什么要alloc, init
alloc 中主要是完成對(duì)象內(nèi)存的分配, init 則是完成初始化.
不 init 可不可以.
可以, 但是對(duì)象還沒(méi)有完成初始化, 內(nèi)存里面除了 isa 指針指向類對(duì)象之外, 其他地方都是空的. 但是調(diào)用簡(jiǎn)單的方法還是可以的, 例如:
@interface MyClass:NSObject
@end
@implementation MyClass
-(void) say {
NSLog(@"hello, world");
}
@end
...
MyClass *obj = [MyClass alloc];
[obj say]; // hello, world
...
- init 方法里面為什么要
self = [super init]
通常的初始化方法是這樣的:
-(instancetype)init
{
self = [super init];
if (self) {
// 初始化
}
return self;
}
我覺(jué)得有兩點(diǎn)原因, 1. 通過(guò)調(diào)用 super init 方法, 可以由繼承鏈完成子類到祖先類的初始化. 2. 如果某個(gè)父類初始化失敗, 可以保證一致性, 不會(huì)出現(xiàn)父類初始化失敗了, 子類還能初始化成功引發(fā)某些奇怪的錯(cuò)誤.
- super 和 self 是什么?
self 比較簡(jiǎn)單, 就是自己, 當(dāng)前接收消息的對(duì)象, 的指針.
super 是什么呢?
這個(gè)得要從 oc 的message send 說(shuō)起. 對(duì)于self 或是一個(gè)普通的對(duì)象, 調(diào)用某個(gè)方法, 例如:
@interface Father:NSObject
@end
@implementation Father
-(void) say {
NSLog(@"hello, i'm father");
}
@end
@interface Son:Father
@end
@implementation Son
-(void) say {
NSLog(@"hello, i'm son");
}
@end
如果在 Son 中調(diào)用 [self say], 將會(huì)轉(zhuǎn)換為偽代碼 msg_send(self, @selector(say)), 這將會(huì)從當(dāng)前 類的方法列表中開(kāi)始查找 say 方法, 如果找不到則往上找, 這里會(huì)輸出hello, i'm son
如果在 Son 調(diào)用 [super say], 將會(huì)轉(zhuǎn)換為偽代碼 objc_msgSendSuper(self, @selector(say)), 這將會(huì)從父類 類的方法列表中開(kāi)始查找 say 方法, 如果找不到則往繼續(xù)往上找, 這里輸出hello, i'm father
可以看到, super 和 self 唯一的區(qū)別是查找方法的起始位置不同. 但是最終接收消息的都是 self. 我們來(lái)驗(yàn)證一下.
改造一下這兩個(gè)類, 分別加一個(gè) name 方法, 然后在 say 中輸出.
@interface Father:NSObject
@end
@implementation Father
-(NSString *)name {
return @"Tom";
}
-(void) say {
NSLog(@"hello, i'm father, my name is %@", self.name);
}
@end
@interface Son:NSObject
@end
@implementation Son
-(NSString *)name {
return @"Tomson";
}
-(void) say {
NSLog(@"hello, i'm son, my name is %@", self.name);
}
@end
如果在 Son 中調(diào)用 [self say], [super say], 會(huì)輸出什么呢?

是不是很奇怪.
結(jié)果中可以看出來(lái), 你是不是期待輸出這樣的結(jié)果.
hello, i'm son, my name is Tom
hello, i'm father, my name is Tomson
失望吧!
雖然看起來(lái)不對(duì)勁, 但從 say 方法來(lái)講, self 調(diào)用的是 Son 的方法, super 調(diào)用的是 Father 的方法, 這點(diǎn)還是沒(méi)問(wèn)題的.
重點(diǎn)在 say 里面的 self.name, 為啥都是調(diào)用的子類的方法?
敲黑板~~~~
之前說(shuō)過(guò), super 只是尋找方法的起點(diǎn)是父類, 真正接收消息的還是子類, 而 super 中的 self 則是指向的當(dāng)前接收消息的對(duì)象.
所以看到 [super say] 是調(diào)用的父類的,因?yàn)檫@個(gè)方法是從父類開(kāi)始找的, 自然就是調(diào)用父類的方法.
self.name 是調(diào)用的子類的, 因?yàn)檎嬲邮障⒌倪€是子類的對(duì)象.
同理, 經(jīng)典問(wèn)題, 期末必考的那種, 再次敲黑板~~~~
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
為啥都是輸出 Son? 是不是有點(diǎn)懂了.不懂?
這是由于 class 這個(gè)方法, 子類和父類都是沒(méi)有實(shí)現(xiàn)的. 真正實(shí)現(xiàn)的是 NSObject, 所以不管是用 self 從當(dāng)前類的方法列表中開(kāi)始查找還是用 super 從父類的方法列表中開(kāi)始查找都沒(méi)有區(qū)別.
最后到 NSObject 里面, 例如如下偽代碼
-(Class)class {
return object_getClass(self);
}
接受消息的是 self 都是 Son 的對(duì)象, 所以打印出來(lái)的也都是 Son
ps:菜鳥(niǎo)一枚, 如果有哪里說(shuō)錯(cuò)的, 還望賜教.