iOS源碼解析:runtime<三>super,isKindOfClass,isMemberOfClass

一 super的本質(zhì)

先從一個(gè)面試題開始探討super相關(guān)的問(wèn)題。有一個(gè)Person類和一個(gè)Student類,Student類繼承自Person類。現(xiàn)在在Student類的init方法中有如下打印:

        NSLog(@"[self class] = %@", [self class]);
        NSLog(@"[super class] = %@", [super class]);
        NSLog(@"[self superclass] = %@", [self superclass]);
        NSLog(@"[super superclass] = %@", [super superclass]);

問(wèn)打印結(jié)果是什么。
按照以前的理解,第一個(gè)應(yīng)該是Student類的類對(duì)象,第二個(gè)是student類的父類的類對(duì)象,也就是Person類的類對(duì)象,第三個(gè)也是Student類的父類的類對(duì)象,第四個(gè)是Student類的父類的父類的類對(duì)象也就是NSObject類的類對(duì)象。
那么真實(shí)的打印情況是不是這樣?我們看一下:

2018-09-17 15:54:02.224686+0800 TEST[8409:174143] [self class] = Student
2018-09-17 15:54:02.224922+0800 TEST[8409:174143] [super class] = Student
2018-09-17 15:54:02.225040+0800 TEST[8409:174143] [self superclass] = Person
2018-09-17 15:54:02.225922+0800 TEST[8409:174143] [super superclass] = Person

通過(guò)打印結(jié)果可以看到,第二個(gè)和第四個(gè)與我之前理解的不一致,這是為什么呢?[super class]的打印結(jié)果為什么是Student呢?在搞清楚這些問(wèn)題之前,我們先搞清楚classsuperclass方法的實(shí)現(xiàn)。我在runtime的NSObject.mm文件中找到了實(shí)現(xiàn)的源碼:

/*******************************************************
 
 + (Class)class {
 return self;
 }
 
 - (Class)class {
 return object_getClass(self);
 }
 
 + (Class)superclass {
 return self->superclass;
 }
 
 - (Class)superclass {
 return [self class]->superclass;
 }
 //通過(guò)對(duì)象的isa指針獲取類的類對(duì)象
Class object_getClass(id obj)
 {
 if (obj) return obj->getIsa();
 else return Nil;
 }

Class class_getSuperclass(Class cls)
{
    if (!cls) return nil;
    return cls->superclass;
}
******************************************************/

為了搞清楚super的實(shí)現(xiàn),我在Person類中實(shí)現(xiàn)run方法,然后在Student類的init方法中使用[super run]來(lái)調(diào)用,然后將其轉(zhuǎn)化為C++的源碼,找到[super run]的實(shí)現(xiàn):

((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));

簡(jiǎn)化一下:

objc_msgSendSuper(__rw_objc_super{
self, 
class_getSuperclass(objc_getClass("Student")}, 
@selector(run));

我們可以看到,這個(gè)objc_msgSendSuper()函數(shù)中傳入了兩個(gè)參數(shù),一個(gè)是一個(gè)結(jié)構(gòu)體:

__rw_objc_super{
self, 
class_getSuperclass(objc_getClass("Student")}

還有一個(gè)就是消息@selector(run)
第一個(gè)參數(shù)這個(gè)結(jié)構(gòu)體中有兩個(gè)成員變量,一個(gè)是self也就是Student實(shí)例對(duì)象,還有一個(gè)是Student類的父類的類對(duì)象,也即是Person類的類對(duì)象。

struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};

第一個(gè)成員是消息接收者,第二個(gè)參數(shù)是父類對(duì)象。
我們?cè)倏匆幌?code>objc_msgSendSuper的實(shí)現(xiàn):

B73B6288-0DF7-4ADB-B273-BA69B6CC2CA3.png

這個(gè)解釋已經(jīng)非常清楚了,也就是objc_msgSendSuper()中相當(dāng)于傳入了三個(gè)參數(shù):objc_msgSendSuper(object ,superclass, @selector(run)),第一個(gè)參數(shù)是消息的接收者,第二個(gè)參數(shù)決定了從這個(gè)父類對(duì)象開始尋找方法的實(shí)現(xiàn),第三個(gè)參數(shù)就是消息。

回到[super run],這個(gè)方法也就是給student對(duì)象發(fā)送@selector(run)消息,但是查找run方法的實(shí)現(xiàn)要從Student類的父類對(duì)象也即是Person類的類對(duì)象中開始查找。

[self class]

就是通過(guò)實(shí)例對(duì)象的isa指針找到找到其類對(duì)象,所以打印是Student。

 [super class]

是給self對(duì)象發(fā)送@selector(class)消息,但是class方法的實(shí)現(xiàn)要從Person類對(duì)象開始查找。class方法是在基類NSObject類中實(shí)現(xiàn)的,所以不管是從Student類對(duì)象中開始查找還是從Person類對(duì)象中開始查找方法的實(shí)現(xiàn),做種都是找打NSObject的實(shí)現(xiàn)中,所以[self class][super class]并無(wú)差異,打印都是Student。

[self superclass]

這個(gè)獲取的就是自己的類對(duì)象的superclass指針的指向,就是父類的類對(duì)象,所以打印是Person。

[super superclass]

這個(gè)其實(shí)和第二個(gè)的情況是一樣的,給student對(duì)象發(fā)送@selector(superclass)消息,但是superclass的實(shí)現(xiàn)要從父類Person類的類對(duì)象開始找起,但是superclass的實(shí)現(xiàn)是基類NSObject類實(shí)現(xiàn)的,所以從Student類的類對(duì)象和Person類的類對(duì)象開始查是沒有區(qū)別的。最終輸出都是student對(duì)象的父類對(duì)象,打印結(jié)果是Person。

二 isKindOfClass ,isMemberOfClass

再來(lái)看一個(gè)面試題,看下面的打印結(jié)果:

        BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
        BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL res3 = [[Person class] isKindOfClass:[Person class]];
        BOOL res4 = [[Person class] isMemberOfClass:[Person class]];

        NSLog(@"%d, %d, %d, %d", res1, res2, res3, res4);

我們首先看一下打印結(jié)果:

1, 0, 0, 0

在分析這個(gè)問(wèn)題之前,我們先查看isMemberOfClass:isKindOfClass:的源碼來(lái)搞明白其具體實(shí)現(xiàn):

/*******************************************
//object_getClass()取得的是對(duì)象的isa指針指向的對(duì)象,也就是判斷傳入的類對(duì)象的元類對(duì)象是否與傳入的這個(gè)對(duì)象相等,所以這個(gè)cls應(yīng)該是元類對(duì)象才有可能相等
 + (BOOL)isMemberOfClass:(Class)cls {
 return object_getClass((id)self) == cls;
 }

 判斷傳入的實(shí)例對(duì)象的類對(duì)象是否與傳入的對(duì)象相等,所以cls只有可能是類對(duì)象才有可能相等
 - (BOOL)isMemberOfClass:(Class)cls {
 return [self class] == cls;
 }
 
//循環(huán)判斷傳入的類對(duì)象的元類對(duì)象及其父類的元類對(duì)象是否等于傳入的cls
 + (BOOL)isKindOfClass:(Class)cls {
 for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
 if (tcls == cls) return YES;
 }
 return NO;
 }
 
//循環(huán)判斷實(shí)例對(duì)象的父類的類對(duì)象是否等于傳入的對(duì)象cls,也就是判斷實(shí)例對(duì)象是否是cls及其子類的一種
 - (BOOL)isKindOfClass:(Class)cls {
 for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
 if (tcls == cls) return YES;
 }
 return NO;
 }
****************************************/

通過(guò)這個(gè)兩個(gè)方法的源碼我們可以知道,isMemberOfClass:是檢測(cè)方法調(diào)用者對(duì)象的類是否等于傳入的這個(gè)類。isKindOfClass:是判斷方法調(diào)用者對(duì)象的類是否等于傳入的這個(gè)類或者其子類。還有一個(gè)適用于這四個(gè)方法的一點(diǎn)是,如果方法調(diào)用者是實(shí)例對(duì)象,那么傳入的就應(yīng)該是類對(duì)象;如果方法調(diào)用者是類對(duì)象,那么傳入的就應(yīng)該是元類對(duì)象。
下面先從第二個(gè)開始分析:

[[NSObject class] isMemberOfClass:[NSObject class]];

方法調(diào)用者是[NSObject class]也就是類對(duì)象,但是傳入的參數(shù)也是類對(duì)象,所以很顯然打印結(jié)果是0。
帶三個(gè):

[[Person class] isKindOfClass:[Person class]];

方法的調(diào)用者是類對(duì)象,傳入的參數(shù)也是類對(duì)象,所以打印結(jié)果是0。
第四個(gè):

[[Person class] isMemberOfClass:[Person class]];

方法調(diào)用者是類對(duì)象,傳入的參數(shù)也是類對(duì)象,所以打印的是0。
最后來(lái)看第一個(gè):

[[NSObject class] isKindOfClass:[NSObject class]];

按照和上面一樣的分析,方法調(diào)用者和傳入的對(duì)象都是類方法,那么應(yīng)該打印0才對(duì)呀,為何會(huì)打印1呢?我們回過(guò)頭去看一下+ (BOOL)isKindOfClass:(Class)cls;的實(shí)現(xiàn):

//循環(huán)判斷傳入的類對(duì)象的元類對(duì)象及其父類的元類對(duì)象是否等于傳入的cls
 + (BOOL)isKindOfClass:(Class)cls {
 for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
 if (tcls == cls) return YES;
 }
 return NO;
 }

我們看到這個(gè)實(shí)現(xiàn)方法,object_getClass((id)self)是先獲得元類方法,判斷其是否等于cls,然后沿著繼承鏈取元類對(duì)象的superclass,我們想一下,當(dāng)沿著繼承鏈,一直不滿足tcls == cls時(shí),最終會(huì)找到NSObject類,取NSObject類的元類的superclass,而NSOBject的元類的superclass指向的是NSOBject類的類對(duì)象,所以打印輸出是1。

三 一個(gè)很繞的面試題

Person類中有一個(gè)屬性叫name,Person類中還有一個(gè)print方法用來(lái)打印name屬性:

//Person.m
- (void)print{
    
    NSLog(@"my name is %@", self.name);
    
}

問(wèn)題是下面這段代碼的打印結(jié)果:

//ViewController.m
- (void)viewDidLoad {
    [super viewDidLoad];

    id cls = [Person class];
    void *obj = &cls;
    
    [(__bridge id)obj print];
    
}

如果在正常工作中寫出這種代碼會(huì)被炒魷魚的,繞來(lái)繞去非常古怪,但是如果是學(xué)習(xí)的話還是可以好好探究一番。
首先我們還是來(lái)看一下打印結(jié)果吧:

 my name is <ViewController: 0x7fd18a50a550>

通過(guò)打印結(jié)果,這里面有兩個(gè)疑惑:

  • 1.print是一個(gè)實(shí)例方法但是代碼中自始至終沒有創(chuàng)建實(shí)例對(duì)象,只有一個(gè)類對(duì)象,那么為什么能夠調(diào)用對(duì)象方法呢?
  • 2.即使能夠調(diào)用對(duì)象方法,為什么打印出來(lái)的是ViewController的地址呢?

下面我們先來(lái)分析一下

    id cls = [Person class];
    void *obj = &cls;

這兩句代碼。
首先創(chuàng)建了一個(gè)id類型的cls指針指向Person類對(duì)象。然后又創(chuàng)建了一個(gè)指針變量obj,obj中存放的是cls的地址,用圖表示其結(jié)構(gòu)如下:


B189B48F-6F9B-4CC2-BB5E-685DA98D3593.png

然后我們?cè)倏聪旅嬉痪浯a:

Person *person = [[Person alloc] init];

這里創(chuàng)建了一個(gè)Person類型的指針變量指向alloc出來(lái)的Person實(shí)例對(duì)象。Person實(shí)例對(duì)象的結(jié)構(gòu)其實(shí)就是一個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體里面存放著isa指針和成員變量,具體到Person實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象中存放著指向Person類對(duì)象的isa指針和_name成員變量。由于person對(duì)象的第一個(gè)成員變量是isa指針,所以person指針指向的其實(shí)就是isa指針?biāo)诘膬?nèi)存,所以其結(jié)構(gòu)圖如下:

1967A83F-D717-41FA-B3CC-68773BE60D64.png

對(duì)比一下上下兩個(gè)圖,是否非常相似呢?
調(diào)用[person print]時(shí),通過(guò)person指針獲取person實(shí)例對(duì)象的地址值,取這個(gè)實(shí)例對(duì)象的地址值的前8字節(jié),就是isa指針了,然后取出isa指針中的地址值,就可以訪問(wèn)類對(duì)象了,然后找到類對(duì)象中的print方法進(jìn)行調(diào)用。

那么對(duì)于obj指針也是一樣的,對(duì)于[obj print],通過(guò)obj指針獲取cls指針的起始位置,同樣可以取其前八字節(jié)(雖然整個(gè)cls只占8字節(jié),但是沒關(guān)系),作為'isa'指針,然后讀出其地址值,就可以獲取類對(duì)象,從而調(diào)用其中的方法。
這樣就回答了第一個(gè)問(wèn)題,即為什么obj能調(diào)用對(duì)象方法。

對(duì)于第二個(gè)問(wèn)題,我們?cè)赾ls指針前面創(chuàng)建一個(gè)字符串試試:

    NSString *str = @"test";
    
    id cls = [Person class];
    void *obj = &cls;
    
    [(__bridge id)obj print];

看一下打印結(jié)果:

my name is test

這就很神器了,居然打印出來(lái)的死str字符串的值,那么我們?cè)僭囍赾ls指針前面創(chuàng)建一個(gè)NSObject對(duì)象試試:

    NSObject *object = [[NSObject alloc] init];
    
    id cls = [Person class];
    void *obj = &cls;
    
    [(__bridge id)obj print];

打印結(jié)果:

my name is <NSObject: 0x6040000074c0>

打斷點(diǎn)后證實(shí)object對(duì)象的地址正是打印的地址,也就是打印的是object對(duì)象,這就很玄乎了。

我們先來(lái)搞清楚一個(gè)問(wèn)題,棧空間的分配是從高地址開始分配還是低地址開始分配?我們?cè)囼?yàn)一下便知道:

    NSObject *obj1 = [[NSObject alloc] init];
    NSObject *obj2 = [[NSObject alloc] init];
    NSObject *obj3 = [[NSObject alloc] init];
    NSObject *obj4 = [[NSObject alloc] init];
    
    NSLog(@"%p, %p, %p, %p", &obj1, &obj2, &obj3, &obj4);

打印結(jié)果:

0x7ffeeec26ac8, 0x7ffeeec26ac0, 0x7ffeeec26ab8, 0x7ffeeec26ab0

obj1,obj2,obj3,obj4都是局部變量,分配在棧區(qū),可以看到,obj1的地址位最高,是0x7ffeeec26ac8,由于指針變量占8字節(jié),所以obj2的地址是在此基礎(chǔ)上減8,也就是0x7ffeeec26ac0,obj3的地址是在obj2的基礎(chǔ)上減8。
這就說(shuō)明棧區(qū)的內(nèi)存是從高地址到低地址分配的。
我們?cè)賮?lái)分析下下面代碼的內(nèi)存關(guān)系:

    NSString *str = @"test";
    
    id cls = [Person class];
    void *obj = &cls;
    
    [(__bridge id)obj print];

首先在棧空間分配了一個(gè)NSString類型的指針str,這個(gè)指針指向常量區(qū)的test字符串,然后在低8字節(jié)的棧空間又分配了一個(gè)id類型的指針cls,這個(gè)指針指向Person類對(duì)象,然后又在低8字節(jié)的占空間分配了一個(gè)指針obj,這個(gè)指針是指向cls指針的。test,cls,obj它們的地址四連續(xù)分配的。
0B1DBBE3-25B0-4851-BE0E-743E718696B4.png

我們知道print方法是打印self.name,也就是讀取person對(duì)象的成員變量_name的值,由于Person類只有一個(gè)屬性name,所以其實(shí)例對(duì)象的結(jié)構(gòu)也是非常簡(jiǎn)單的,就是一個(gè)isa指針和一個(gè)_name成員變量。[person print]是怎樣去獲取_name的值的呢?
person指針指向的是person實(shí)例對(duì)象的地址,person實(shí)例對(duì)象的前8字節(jié)是isa指針,那么只需要讀取person指針的地址,從這個(gè)地址開始的前8字節(jié)就是isa指針,同理,再往下取8字節(jié)就是_name成員變量的值。

那么[obj print]也是一樣的,obj指針把cls當(dāng)做了person實(shí)例對(duì)象,所以它會(huì)怎么去取_name的值呢?還是一樣的,通過(guò)obj存放的地址獲取cls的起始地址,然后讀從這個(gè)起始地址開始的前八字節(jié)當(dāng)做isa指針,再往后取8字節(jié)當(dāng)做_name成員變量的值。cls往后取第9到16字節(jié)的值正是@"test"字符串,所以打印出來(lái)的也就是字符串。

現(xiàn)在我們?cè)倩氐皆瓉?lái)的問(wèn)題,為什么打印的是<ViewController: 0x7fd18a50a550>也就是視圖控制器對(duì)象。
我們來(lái)分析一下下面的一句代碼:

[super viewDidLoad];

我們?cè)诘谝徊糠志椭v過(guò)super調(diào)用的問(wèn)題,這段代碼的本質(zhì)就是:

objc_msgSendSuper({self,
    class_getSuperclass(objc_getClass("ViewController"))},
    @selector(viewDidLoad))

第一個(gè)參數(shù)傳入的是一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體如下:

    struct objc_super{
        self,
        class_getSuperclass(objc_getClass("ViewController"))
    };

那么[super viewDidLoad];也就相當(dāng)于聲明了一個(gè)結(jié)構(gòu)體類型的局部變量,這個(gè)局部變量有兩個(gè)成員,所有新的內(nèi)存結(jié)構(gòu)如下:

3D9435C6-D124-4816-B653-D178A0EC5AFF.png

這個(gè)時(shí)候去調(diào)用print,讀取的_name也即是self,就是控制器了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評(píng)論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,751評(píng)論 0 9
  • 前言:本文簡(jiǎn)述OC對(duì)象、isa和SuperClass,如有錯(cuò)誤請(qǐng)留言指正。 Q:OC中對(duì)象分類 A:總共為三類:實(shí)...
    夢(mèng)蕊dream閱讀 4,135評(píng)論 6 16
  • 我們常常會(huì)聽說(shuō) Objective-C 是一門動(dòng)態(tài)語(yǔ)言,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,225評(píng)論 0 7
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,478評(píng)論 8 265
  • iOS底層原理總結(jié) - 探尋OC對(duì)象的本質(zhì) 對(duì)小碼哥底層班視頻學(xué)習(xí)的總結(jié)與記錄。面試題部分,通過(guò)對(duì)面試題的分析探索...
    xx_cc閱讀 21,506評(píng)論 31 178