iOS Objective-C 中的 self 與 super

  1. 為什么要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
...
  1. 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ò)誤.

  1. 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é)果吧

是不是很奇怪.
結(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ò)的, 還望賜教.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,068評(píng)論 0 9
  • 20- 枚舉,枚舉原始值,枚舉相關(guān)值,switch提取枚舉關(guān)聯(lián)值 Swift枚舉: Swift中的枚舉比OC中的枚...
    iOS_恒仔閱讀 2,428評(píng)論 1 6
  • 【禪語(yǔ)】 真正的幸福就在你的身邊,在你的心里。在浮躁的生活里,我們或者大喜,或者大悲,或者悲喜交加。其實(shí)看淡了看簡(jiǎn)...
    武漢如心閱讀 383評(píng)論 3 4
  • 天地間仿佛只剩我一人,徹骨的寒涼襲擊著我,沒(méi)走一步仿佛都將抽走全身的氣力。我精心維護(hù)的愛(ài)人,刻入骨髓的愛(ài)意已被現(xiàn)實(shí)...
    尋覓09閱讀 236評(píng)論 0 0

友情鏈接更多精彩內(nèi)容