iOS類的本質(zhì)

首先娘荡,我們看下幾個(gè)類型:NSObjectClass祭钉、objc_object瞄沙、objc_classid的聯(lián)系與區(qū)別慌核。

  • NSObject:OC中的基類距境,絕大多數(shù)類都繼承NSObjectNSProxy也是基類哦~)
  • Class:NSObject的類型,在objc源碼的NSObject.mm文件中可以看到
+ (Class)class {
    return self;
}
  • objc_object:NSObject類在C++的底層實(shí)現(xiàn)的結(jié)構(gòu)體名稱,在生成的cpp文件中可以看到,它和NSObject是同一個(gè)東西咙冗,只是在不同語(yǔ)言環(huán)境的名字不同。objc_object結(jié)構(gòu)體里面诬滩,只有一個(gè)成員變量isa指針。
typedef struct objc_object NSObject;

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
  • objc_class:Class在C++底層實(shí)現(xiàn)的結(jié)構(gòu)體名稱灭将,在生成的cpp文件中可以看到疼鸟,它和Class是同一個(gè)東西,只是在不同語(yǔ)言環(huán)境的名字不同庙曙。
typedef struct objc_class *Class;
  • id:OC環(huán)境中可以指向任何類型空镜,并且不用帶*號(hào)
typedef struct objc_object *id;
isa與superClass探究

我們先看下類在內(nèi)存中地址,是不是每創(chuàng)建一對(duì)象捌朴,都會(huì)創(chuàng)建一個(gè)新的與之對(duì)應(yīng)的類吴攒。

void getSJPersonClass(void) {
    Class cls1 = SJPerson.class;
    Class cls2 = [SJPerson alloc].class;
    Class cls3 = object_getClass([SJPerson alloc]);
    Class cls4 = [SJPerson alloc].class;
    NSLog(@"cls1 : %p \n cls1 : %p \n cls1 : %p \n cls1 : %p \n", cls1, cls2, cls3, cls4);
}

執(zhí)行getSJPersonClass,打印結(jié)果如下:

image

也就是同樣的類砂蔽,在內(nèi)存中只會(huì)有1份洼怔。

我們打印實(shí)例變量p的內(nèi)存,我們知道前8位是isa指針

image

isa地址與ISA_MASK做與運(yùn)算左驾,可以拿到類對(duì)象的地址镣隶。

image

我們繼續(xù)拿類的isa地址與ISA_MASK做與運(yùn)算,看可以得到什么诡右。

image

我們看到安岂,最后打印的結(jié)果也是SJPerson,但是兩個(gè)SJPerson的地址不一樣稻爬,一個(gè)0x00000001000085f8嗜闻,一個(gè)0x00000001000085d0蜕依,也就是說(shuō)這兩個(gè)不是一個(gè)類型桅锄。在這就不賣(mài)關(guān)子了琉雳,第二個(gè)SJPerson就是我們常說(shuō)的元類。
為什么是元類呢友瘤,我們可以在machOView中找到相關(guān)內(nèi)容:
image

看到有一個(gè)metaclass也就是元類翠肘。
那我們繼續(xù)看下元類的isa指向哪里。
image

我們看到SJPerosn元類的isa打印出來(lái)是ONObject辫秧,但是地址和NSObject類對(duì)象地址不一樣束倍,我們?cè)诖蛴?code>NSObject的元類地址,發(fā)現(xiàn)地址一致了盟戏,也就是說(shuō)SJPerson的元類的isa指向NSObject元類绪妹。SJPerson繼承自NSObject,那是不是說(shuō)明直接指向父類的元類呢柿究,我們?cè)賱?chuàng)建一個(gè)SJStudent繼承SJPerson邮旷,再試一下。

image

image

我們看到$3$5相同蝇摸,也就是說(shuō)婶肩,無(wú)論對(duì)象繼承誰(shuí),自定義對(duì)象的元類的isa都指向根元類貌夕。
繼續(xù)往下律歼,我們看下NSObject元類的isa指向哪里。
image

1與2相同啡专,也就是說(shuō)根元類的isa指向它自己险毁。
isa指向鏈我們看完了,再看下繼承關(guān)系植旧,元類也有繼承嗎辱揭,我們用以下代碼測(cè)試以下:

NSObject *obj = [NSObject alloc];
    Class objCls = object_getClass(obj);
    Class objMetaCls = object_getClass(objCls);
    Class objRootMetaCls = object_getClass(objMetaCls);
    NSLog(@"NSObject實(shí)例對(duì)象: %p \n NSObject類對(duì)象: %p \n NSObject元類對(duì)象: %p \n NSObject根元類對(duì)象: %p \n ", obj, objCls, objMetaCls, objRootMetaCls);
    
    Class pMetaCls = object_getClass([SJPerson class]);
    Class pMetaSuperCls = class_getSuperclass(pMetaCls);
    NSLog(@"SJPerson元類對(duì)象: %p \n SJPerson元類對(duì)象的父類: %p \n ", pMetaCls, pMetaSuperCls);
    
    Class sMetaCls = object_getClass([SJStudent class]);
    Class sMetaSuperCls = class_getSuperclass(sMetaCls);
    NSLog(@"SJStudent元類對(duì)象: %p \n SJStudent元類對(duì)象的父類: %p \n ", sMetaCls, sMetaSuperCls);
    
    Class rootMetaSuperCls = class_getSuperclass(objRootMetaCls);
    NSLog(@"根元類對(duì)象的父類: %p", rootMetaSuperCls);

打印結(jié)果:

NSObject實(shí)例對(duì)象: 0x101a30050 
NSObject類對(duì)象: 0x10036a140 
NSObject元類對(duì)象: 0x10036a0f0 
NSObject根元類對(duì)象: 0x10036a0f0 
 
SJPerson元類對(duì)象: 0x100008530 
SJPerson元類對(duì)象的父類: 0x10036a0f0 
 
SJStudent元類對(duì)象: 0x100008580 
SJStudent元類對(duì)象的父類: 0x100008530 
 
根元類對(duì)象的父類: 0x10036a140

根據(jù)結(jié)果,我們看到SJStudent元類的父類就是SJPerson元類病附,SJPerson元類的父類就是NSObject的元類问窃,NSObject元類的父類就是NSObject類對(duì)象。
isa的流程圖與繼承流程圖如下:

image

類的內(nèi)存數(shù)據(jù)

OC的類在C++中是objc_class類型完沪,我們?cè)?code>objc源碼中找objc_class的結(jié)構(gòu)域庇。
我們找到3個(gè)結(jié)構(gòu)

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

因?yàn)槲覀儺?dāng)前環(huán)境是OBJC2,所以這個(gè)標(biāo)明OBJC2_UNAVAILABLE覆积,我們就可以忽略不計(jì)听皿。
還有兩個(gè)分別在objc-runtime-new.hobjc-runtime-old.h文件中,我們想都不想直接看new宽档。里面的結(jié)構(gòu)省略方法后:

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
}

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

也就是說(shuō)尉姨,類結(jié)構(gòu)里面有isa指針,superclass吗冤,cache又厉,bits九府。isa我們已經(jīng)分析過(guò)了,superclass就是父類覆致,cache我們以后再說(shuō)侄旬,我們接下來(lái)研究下bits
在此之前我們驗(yàn)證下superclass:

image

SJPerson的父類是NSObject煌妈,沒(méi)有問(wèn)題儡羔。
要研究bits,首先我們需要知道bits在內(nèi)存存儲(chǔ)的位置璧诵,isa占8字節(jié)汰蜘,superclass占8字節(jié)沒(méi)什么好說(shuō)的,那么cache占多少字節(jié)呢之宿,我們點(diǎn)進(jìn)去看下cache_t的結(jié)構(gòu):

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;
#if __LP64__
            uint16_t                   _flags;
#endif
            uint16_t                   _occupied;
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;
    };
}

再看下explicit_atomic實(shí)現(xiàn)

template <typename T>
struct explicit_atomic : public std::atomic<T> {
    explicit explicit_atomic(T initial) noexcept : std::atomic<T>(std::move(initial)) {}
    operator T() const = delete;
    
    T load(std::memory_order order) const noexcept {
        return std::atomic<T>::load(order);
    }
    void store(T desired, std::memory_order order) noexcept {
        std::atomic<T>::store(desired, order);
    }
    
    // Convert a normal pointer to an atomic pointer. This is a
    // somewhat dodgy thing to do, but if the atomic type is lock
    // free and the same size as the non-atomic type, we know the
    // representations are the same, and the compiler generates good
    // code.
    static explicit_atomic<T> *from_pointer(T *ptr) {
        static_assert(sizeof(explicit_atomic<T> *) == sizeof(T *),
                      "Size of atomic must match size of original");
        explicit_atomic<T> *atomic = (explicit_atomic<T> *)ptr;
        ASSERT(atomic->is_lock_free());
        return atomic;
    }
};

T泛型鉴扫,這個(gè)變量的大小取決于泛型T的大小。uintptr_t指針占8字節(jié)澈缺,第二個(gè)變量共用體坪创,mask_ttypedef uint32_t mask_t;,占4字節(jié)姐赡,uint16_t占2字節(jié)莱预,結(jié)構(gòu)體占8字節(jié),_originalPreoptCache是個(gè)*也就是指針類型也是8字節(jié)项滑,所以依沮,cache_t一共占16字節(jié)。bits從32字節(jié)開(kāi)始枪狂。
再看下怎么獲取bits里面數(shù)據(jù)危喉,在源碼中可以找到data方法。

class_rw_t *data() const {
        return bits.data();
    }

image

里面唯一能根據(jù)單詞猜意思的只有firstSubclass州疾,第一個(gè)子類辜限,但是SJPerson有一個(gè)子類SJStudent啊,為什么這里面數(shù)據(jù)是nil呢严蓖?因?yàn)镺C中的類是懶加載的薄嫡,如果沒(méi)有用到,是不會(huì)加載這個(gè)類颗胡,那我們代碼改一下:

SJStudent *s = [SJStudent alloc];
SJPerson *p = [SJPerson alloc];

image

這時(shí)候我們就看到firstSubclass里面有值了毫深,沒(méi)毛病。但是我又想毒姨,如果SJPerson還有別的子類哑蔫,這個(gè)值又會(huì)是什么呢?
新建一個(gè)SJHandsomeMan繼承自SJPerson
image

image

兩次結(jié)果不一樣闸迷,也就是說(shuō)firstSubclass的值是該類子類中最后初始化的那個(gè)類瘩蚪。

類的屬性

目前能看懂看完了,比如我們想看類里面的屬性怎么辦呢稿黍?答:從class_rw_t結(jié)構(gòu)里面找成員變量或者方法。

const property_array_t properties() const {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t *>()) {
        return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
    } else {
        return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
    }
}

成員變量沒(méi)找到崩哩,方法倒是看上去有一個(gè)巡球,那我們接著調(diào)試。

class property_array_t : 
    public list_array_tt<property_t, property_list_t, RawPtr>
{
    typedef list_array_tt<property_t, property_list_t, RawPtr> Super;

 public:
    property_array_t() : Super() { }
    property_array_t(property_list_t *l) : Super(l) { }
};
template <typename Element, typename List, template<typename> class Ptr>
class list_array_tt {
    struct array_t {
        uint32_t count;
        Ptr<List> lists[0];

        static size_t byteSize(uint32_t count) {
            return sizeof(array_t) + count*sizeof(lists[0]);
        }
        size_t byteSize() {
            return byteSize(count);
        }
    };
}
struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};
template <typename Element, typename List, uint32_t FlagMask, typename PointerModifier = PointerModifierNop>
struct entsize_list_tt {
    uint32_t entsizeAndFlags;
    uint32_t count;

    uint32_t entsize() const {
        return entsizeAndFlags & ~FlagMask;
    }
    uint32_t flags() const {
        return entsizeAndFlags & FlagMask;
    }

    Element& getOrEnd(uint32_t i) const { 
        ASSERT(i <= count);
        return *PointerModifier::modify(*this, (Element *)((uint8_t *)this + sizeof(*this) + i*entsize()));
    }
    Element& get(uint32_t i) const { 
        ASSERT(i < count);
        return getOrEnd(i);
    }

    size_t byteSize() const {
        return byteSize(entsize(), count);
    }
    
    static size_t byteSize(uint32_t entsize, uint32_t count) {
        return sizeof(entsize_list_tt) + count*entsize;
    }

    struct iterator;
}

分析下property_array_t結(jié)構(gòu):是個(gè)數(shù)組邓嘹,數(shù)組里面每個(gè)元素都是property_list_t類型酣栈,property_list_t也是個(gè)數(shù)組,因?yàn)?code>entsize_list_tt里面有迭代器iterator汹押,property_list_t數(shù)組里面的元素是property_t矿筝。大致結(jié)構(gòu):property_array_t = [property_list_t[property_t, property_t], property_list_t[property_t]]

image

再看下property_t的結(jié)構(gòu):

struct property_t {
    const char *name;
    const char *attributes;
};
類的方法

屬性我們看完了棚贾,再看下方法窖维,在SJPerson里面添加兩個(gè)方法,一個(gè)實(shí)例方法妙痹,一個(gè)類方法铸史。

@interface SJPerson : NSObject

@property (nonatomic, copy) NSString *name;

- (void)sayNB;
+ (void)say666;

@end

找方法同樣我們看到class_rw_t里面有個(gè)methods方法,不出意外應(yīng)該能拿到方法怯伊。

const method_array_t methods() const {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t *>()) {
        return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
    } else {
        return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
    }
}

method_array_t的結(jié)構(gòu)和property_array_t一樣琳轿,都是二維數(shù)組,只不過(guò)最里面的對(duì)象換成了method_t耿芹。

image

我們看到同樣的操作崭篡,怎么最后打印不出來(lái)數(shù)據(jù),是不是我們操作不對(duì)吧秕?這就要說(shuō)下property_t里面有兩個(gè)成員琉闪,打印的時(shí)候直接把兩個(gè)成員打印出來(lái),我們?cè)倏聪?code>method_t的結(jié)構(gòu)里面沒(méi)有這種成員砸彬,但是里面有一個(gè)結(jié)構(gòu)體:

struct big {
    SEL name;
    const char *types;
    MethodListIMP imp;
};

這里面成員能看到方法所有內(nèi)容塘偎,是不是我們打印這個(gè)big就行呢?測(cè)試一下:

image

非常完美方法都打印出來(lái)了拿霉,但是自己觀察吟秩,一共就3個(gè)方法,say666沒(méi)有打印出來(lái)绽淘,為什么呢涵防?對(duì)象方法存在類結(jié)構(gòu)中,那猜測(cè)類方法會(huì)不會(huì)放在元類里面呢?我們來(lái)驗(yàn)證下:

image

image

我們看到say666的確在元類里面壮池,也就是類方法存儲(chǔ)在元類偏瓤。
這也就是為什么iOS要設(shè)計(jì)元類的原因,因?yàn)镺C中有實(shí)例方法和類方法椰憋,也就是所謂的減號(hào)方法和加號(hào)方法厅克,但是在OC底層,是沒(méi)有這個(gè)含義的橙依,也就是所有方法都轉(zhuǎn)化成同名函數(shù)证舟,如果沒(méi)有元類,我們寫(xiě)兩個(gè)方法+(void)say666-(void)say666窗骑,這兩個(gè)方法都存儲(chǔ)在類里面女责,那我們執(zhí)行方法的時(shí)候,根據(jù)函數(shù)名创译,就無(wú)法確定到底是執(zhí)行實(shí)例方法還是類方法了抵知,所以設(shè)計(jì)元類把兩種方法分離開(kāi)。

類的成員變量

class_ro_t演變
在WWDC視頻中软族,我們可以詳細(xì)看到class_ro_t演變優(yōu)化過(guò)程刷喜,也知道成員變量存在class_ro_t中。在SJPerson中添加一個(gè)成員變量hobby立砸。

@interface SJPerson : NSObject
{
    NSString *hobby;
}
@property (nonatomic, copy) NSString *name;
- (void)sayNB;
+ (void)say666;

@end

class_ro_t怎么找呢吱肌,同樣在源碼中找方法

const class_ro_t *ro() const {
    auto v = get_ro_or_rwe();
    if (slowpath(v.is<class_rw_ext_t *>())) {
        return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
    }
    return v.get<const class_ro_t *>(&ro_or_rw_ext);
}

調(diào)試驗(yàn)證:


image

image

TypeEncoding

上面打印方法里面types一堆符號(hào)就是iOS中TypeEncoding編碼,每個(gè)符號(hào)的含義可以參照# Type Encodings
仰禽。
在解釋下方法中types含義:
第一個(gè)字母:返回值類型氮墨。第一個(gè)數(shù)字:這個(gè)方法所有參數(shù)占內(nèi)存大小。
第二個(gè)字母:第一個(gè)參數(shù)的類型吐葵。第二個(gè)數(shù)字:第一個(gè)參數(shù)從第幾號(hào)內(nèi)存開(kāi)始规揪。
第三個(gè)字母:第二個(gè)參數(shù)的類型。第三個(gè)數(shù)字:第二個(gè)參數(shù)從第幾號(hào)內(nèi)存開(kāi)始温峭。
.......以此類推猛铅。

總結(jié):類本質(zhì)就是結(jié)構(gòu)體,里面有isa凤藏,superclass奸忽,cachebits揖庄。isa利用位域存著類相關(guān)信息栗菜,superclass存著父類,cache存著方法緩存蹄梢,bits里面存著屬性列表疙筹、實(shí)例變量列表、方法列表、協(xié)議列表等而咆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霍比,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子暴备,更是在濱河造成了極大的恐慌悠瞬,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涯捻,死亡現(xiàn)場(chǎng)離奇詭異浅妆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)汰瘫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)擂煞,“玉大人混弥,你說(shuō)我怎么就攤上這事《允。” “怎么了蝗拿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蒿涎。 經(jīng)常有香客問(wèn)我哀托,道長(zhǎng),這世上最難降的妖魔是什么劳秋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任仓手,我火速辦了婚禮,結(jié)果婚禮上玻淑,老公的妹妹穿的比我還像新娘嗽冒。我一直安慰自己,他們只是感情好补履,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布添坊。 她就那樣靜靜地躺著,像睡著了一般箫锤。 火紅的嫁衣襯著肌膚如雪贬蛙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天谚攒,我揣著相機(jī)與錄音阳准,去河邊找鬼。 笑死馏臭,一個(gè)胖子當(dāng)著我的面吹牛溺职,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浪耘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乱灵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起七冲,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤痛倚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后澜躺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蝉稳,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年掘鄙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耘戚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡操漠,死狀恐怖收津,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浊伙,我是刑警寧澤撞秋,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站嚣鄙,受9級(jí)特大地震影響吻贿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哑子,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一舅列、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卧蜓,春花似錦剧蹂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至其爵,卻和暖如春冒冬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摩渺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工简烤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摇幻。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓横侦,卻偏偏與公主長(zhǎng)得像挥萌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枉侧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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

  • 類本身也是一個(gè)對(duì)象引瀑,是class類型的對(duì)象. objc_class結(jié)構(gòu)體的定義: 假設(shè)我們創(chuàng)建一個(gè)Person類:...
    Colleny_Z閱讀 1,103評(píng)論 0 3
  • Objective-C代碼,底層實(shí)現(xiàn)其實(shí)都是C\C++代碼榨馁。 使用基本代碼驗(yàn)證對(duì)象是什么: oc代碼: int m...
    小暖風(fēng)閱讀 228評(píng)論 0 0
  • 1.類的本質(zhì) 類的本質(zhì)其實(shí)也是一個(gè)對(duì)象(類對(duì)象)程序中第一次使用該類的時(shí)候被創(chuàng)建憨栽,在整個(gè)程序中只有一份。此后每次使...
    GSChan閱讀 3,105評(píng)論 0 13
  • 我們先來(lái)解釋一下蘋(píng)果官方給開(kāi)發(fā)者提供的這張圖 例如我們創(chuàng)建個(gè)自己的類 LWPerson *person = [[...
    8e750c8f0fae閱讀 193評(píng)論 0 0
  • ??我們這里討論類的結(jié)構(gòu)翼虫,我們先定義2個(gè)類Strudent和Person屑柔,Strudent繼承自Person,Pe...
    愛(ài)看書(shū)de圖圖閱讀 670評(píng)論 2 3