Category--load與initialize

Category的概述以及實(shí)現(xiàn)原理
Category和Class Extension 類擴(kuò)展的區(qū)別
Category中l(wèi)oad方法是什么時(shí)候調(diào)用的辐脖?
使用關(guān)聯(lián)對(duì)象為分類添加成員變量
load 與 initialize 的區(qū)別

作用

分類的主要作用就是在不改變?cè)蓄惖那疤嵯潞耍瑒?dòng)態(tài)地給這個(gè)類添加一些方法。具體在項(xiàng)目中大概有這么幾個(gè)好處:
1唇辨、分類在架構(gòu)設(shè)計(jì)上面可以達(dá)到解耦的效果。 開發(fā)過程中比較繁重啰嗦的業(yè)務(wù)代碼對(duì)項(xiàng)目的可讀性造成了壓力,為追求架構(gòu)清晰幕随,降低維護(hù)成本低豹障,可以通過分類進(jìn)行梳理冯事。典型的就是將項(xiàng)目中 AppDelegate 拆分。 AppDelegate 作為程序的入口血公,一般都會(huì)實(shí)現(xiàn)各種第三方 SDK 的初始化昵仅、寫各種版本的容錯(cuò)代碼、實(shí)現(xiàn)通知、支付邏輯等等功能摔笤,所以 AppDelegate 這個(gè)類很容易臃腫够滑,這個(gè)時(shí)候可以通過實(shí)現(xiàn) AppDelegate 分類來將不同的業(yè)務(wù)代碼分離囊颅。

2穿铆、通過實(shí)現(xiàn)分類的 load 方法來實(shí)現(xiàn) Method Swizzling

3、通過分類來為已知的類擴(kuò)展方法和屬性塞绿,Category 不會(huì)為我們的屬性添加實(shí)例變量和存取方法命辖,我們可以通過關(guān)聯(lián)對(duì)象這個(gè)技術(shù)來實(shí)現(xiàn)對(duì)象綁定

注意事項(xiàng):
1:如果category中有和原有類同名的方法况毅,會(huì)優(yōu)先調(diào)用分類中的方法,就是說會(huì)忽略原有類的方法吮龄。
2:如果多個(gè)分類中都有和原有類中同名的方法俭茧,那么調(diào)用該方法的時(shí)候執(zhí)行誰由編譯器決定,編譯器會(huì)執(zhí)行最后一個(gè)參與編譯的分類中的方法漓帚。
3:過渡使用分類 也會(huì)導(dǎo)致APP項(xiàng)目 支離破碎感+性能降低
4:我們?cè)诜诸愔刑砑恿藢傩灾竽刚到y(tǒng)只是為我們生成了get方法和set方法的聲明,并沒有為我們生成成員變量和方法的實(shí)現(xiàn)
5: 名字相同的分類會(huì)引起編譯報(bào)錯(cuò);

Category 的實(shí)現(xiàn)原理

我們知道 Objective-C 通過 Runtime 運(yùn)行時(shí)來實(shí)現(xiàn)動(dòng)態(tài)語言這個(gè)特性尝抖,所有的類和對(duì)象毡们,在 Runtime 中都是用結(jié)構(gòu)體來表示的,Category 在 Runtime 中是用結(jié)構(gòu)體 category_t 來表示的昧辽,下面是結(jié)構(gòu)體 category_t 具體表示:

typedef struct category_t {
    const char *name;//類的名字 主類名字
    classref_t cls;//類
    struct method_list_t *instanceMethods;//實(shí)例方法的列表
    struct method_list_t *classMethods;//類方法的列表
    struct protocol_list_t *protocols;//所有協(xié)議的列表
    struct property_list_t *instanceProperties;//添加的所有屬性
} category_t;

通過結(jié)構(gòu)體 category_t 可以知道衙熔,在 Category 中我們可以增加實(shí)例方法、類方法搅荞、協(xié)議红氯、屬性。我們這里簡述下 Category 的實(shí)現(xiàn)原理:

1咕痛、在編譯時(shí)期痢甘,會(huì)將分類中實(shí)現(xiàn)的方法生成一個(gè)結(jié)構(gòu)體 method_list_t 、將聲明的屬性生成一個(gè)結(jié)構(gòu)體 property_list_t 茉贡,然后通過這些結(jié)構(gòu)體生成一個(gè)結(jié)構(gòu)體 category_t 塞栅。
2、然后將結(jié)構(gòu)體 category_t 保存下來
3腔丧、在運(yùn)行時(shí)期放椰,Runtime 會(huì)拿到編譯時(shí)期我們保存下來的結(jié)構(gòu)體 category_t。然后將結(jié)構(gòu)體 category_t 中的實(shí)例方法列表愉粤、協(xié)議列表砾医、屬性列表添加到主類中。將結(jié)構(gòu)體 category_t 中的類方法列表科汗、協(xié)議列表添加到主類的 metaClass 中藻烤。

  • 在程序運(yùn)行的時(shí)候,通過Runtime加載某個(gè)類的所有Category數(shù)據(jù),同時(shí)將Category中的方法怖亭、屬性涎显、協(xié)議數(shù)據(jù)合并到一個(gè)大數(shù)組中,后來參與編譯的Category數(shù)據(jù)兴猩,會(huì)在數(shù)組的前面期吓。
  • 將合并后的分類數(shù)據(jù)包括方法、屬性倾芝、協(xié)議等信息讨勤,插入到類原來數(shù)據(jù)的前面,所以這也就造成了如果分類和類中有相同的方法晨另,調(diào)用的時(shí)候會(huì)優(yōu)先調(diào)用分類的方法潭千,而且如果多個(gè)分類中有相同的名稱方法則會(huì)優(yōu)先調(diào)用最后參與編譯的
    編譯順序

例如上圖,如果這兩個(gè)分類中有相同名稱的方法則最終會(huì)調(diào)用紅框中的

因?yàn)樵创a太多 就不在一一貼圖解釋了借尿,這里列舉了源碼的閱讀順序刨晴,感興趣的朋友可以自己嘗試著去仔細(xì)分析一下

objc-os.mm
_objc_init
map_images
map_images_nolock

objc-runtime-new.mm
_read_images
remethodizeClass
attachCategories
attachLists
realloc、memmove路翻、 memcpy

Category 為什么不能添加實(shí)例變量

通過結(jié)構(gòu)體 category_t 狈癞,我們就可以知道,在 Category 中我們可以增加實(shí)例方法茂契、類方法蝶桶、協(xié)議、屬性掉冶。這里沒有 objc_ivar_list 結(jié)構(gòu)體真竖,代表我們不可以在分類中添加實(shí)例變量。

因?yàn)樵谶\(yùn)行期厌小,對(duì)象的內(nèi)存布局已經(jīng)確定疼邀,如果添加實(shí)例變量就會(huì)破壞類的內(nèi)部布局,這個(gè)就是 Category 中不能添加實(shí)例變量的根本原因召锈。

使用關(guān)聯(lián)對(duì)象為分類添加成員變量

上面我們說到 在分類中添加了屬性之后,系統(tǒng)只是為我們生成了get方法和set方法的聲明获询,并沒有為我們生成成員變量和方法的實(shí)現(xiàn)涨岁,下面我們來驗(yàn)證這一說法
我們?yōu)?code>GSPerson對(duì)象添加了一個(gè)分類, 并且在分類中設(shè)置了一個(gè)height的屬性,下面我們來使用一下該分類對(duì)象:

#import "GSPerson.h"
@interface GSPerson (Utility)
@property (nonatomic, assign) int height;
@end
image

我們?yōu)?code>height賦值20 ,運(yùn)行起來之后竟然奔潰了,并且提示我們

reason: '-[GSPerson setHeight:]: unrecognized selector sent to instance 0x1006259a0'

是不是印證了我們的說法?
那么我們?cè)撊绾螢?code>Category添加一個(gè)成員變量呢?答案是關(guān)聯(lián)對(duì)象:
其實(shí)主要涉及到關(guān)聯(lián)對(duì)象的兩個(gè)方法:objc_getAssociatedObjectobjc_setAssociatedObject

/*
 參數(shù)一:id object : 獲取哪個(gè)對(duì)象里面的關(guān)聯(lián)的屬性。
 參數(shù)二:void * == id key : 什么屬性吉嚣,與objc_setAssociatedObject中的key相對(duì)應(yīng)梢薪,即通過key值取出value。
 */
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
/*
參數(shù)一:id object : 給哪個(gè)對(duì)象添加屬性尝哆,這里要給自己添加屬性秉撇,用self
參數(shù)二:void * == id key : 屬性名,根據(jù)key獲取關(guān)聯(lián)對(duì)象的屬性的值,在objc_getAssociatedObject中通過此key獲得屬性的值并返回琐馆。
參數(shù)三:id value : 關(guān)聯(lián)的值规阀,也就是set方法傳入的值給屬性去保存。
參數(shù)四:objc_AssociationPolicy policy : 策略瘦麸,屬性以什么形式保存谁撼。
 */
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy)

其中objc_AssociationPolicy policy策略是個(gè)枚舉值

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,  // 指定一個(gè)弱引用相關(guān)聯(lián)的對(duì)象
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相關(guān)對(duì)象的強(qiáng)引用,非原子性
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  // 指定相關(guān)的對(duì)象被復(fù)制滋饲,非原子性
    OBJC_ASSOCIATION_RETAIN = 01401,  // 指定相關(guān)對(duì)象的強(qiáng)引用厉碟,原子性
    OBJC_ASSOCIATION_COPY = 01403     // 指定相關(guān)的對(duì)象被復(fù)制,原子性   
};

具體的對(duì)應(yīng)關(guān)系如下所示:


了解了這兩個(gè)方法后,為關(guān)聯(lián)對(duì)象添加屬性就非常的簡單了,比如為 GSPerson對(duì)象添加height屬性具體如下:

#import "GSPerson+Utility.h"
#import <objc/runtime.h>
@implementation GSPerson (Utility)
-(void)setHeight:(int)height{
    //key值只要是一個(gè)指針即可屠缭,我們可以傳入@selector(name)
    objc_setAssociatedObject(self, @selector(height), @(height), OBJC_ASSOCIATION_ASSIGN);
    
    //或者    
    //objc_setAssociatedObject(self, @"height", @(height), OBJC_ASSOCIATION_ASSIGN);
}
-(int)height{
   //_cmd == @selector(height)
   return  [objc_getAssociatedObject(self, _cmd) intValue];
   //或者
   //return  [objc_getAssociatedObject(self, @"height") intValue];
   
}
@end

那么問題來了箍鼓,我們用關(guān)聯(lián)對(duì)象為Category添加的成員變量具體是存儲(chǔ)在了哪呢?
下面我們通過一幅圖來了解下關(guān)聯(lián)對(duì)象的本質(zhì):


具體到更直觀的數(shù)據(jù)結(jié)構(gòu)上呵曹,我們可以看下圖

  • 關(guān)聯(lián)對(duì)象是由AssociationManager全局類管理并存儲(chǔ)在AssociationHashMap中款咖。
  • 所有對(duì)象的關(guān)聯(lián)內(nèi)容都存在于一個(gè)全局容器中,和宿主類是無關(guān)的逢并。

Extension 類擴(kuò)展

一般用類擴(kuò)展做什么工作之剧?
  • 聲明私有屬性
  • 聲明私有方法,一般沒有多大用砍聊,只是為了閱讀方便而已
  • 聲明私有成員變量
類擴(kuò)展有什么特點(diǎn)背稼?
  • 編譯時(shí)決議
  • 只以聲明的形式存在,多數(shù)情況下存在于宿主類的.m文件中
  • 不能為系統(tǒng)類添加擴(kuò)展
Category和Class Extension 類擴(kuò)展的區(qū)別

有了上面的特點(diǎn)玻蝌,我們就方便的將分類和擴(kuò)展放到一起比較了蟹肘。

  • 分類是在運(yùn)行時(shí)才會(huì)將數(shù)據(jù)合并到類信息中。而類擴(kuò)展在程序編譯的時(shí)候俯树,它的數(shù)據(jù)就已經(jīng)包含在類信息中了
  • 分類中既可以有聲明也可以有實(shí)現(xiàn)帘腹,而類擴(kuò)展只以聲明的形式存在,多數(shù)情況下存在于宿主類的.m文件中
  • 可以為系統(tǒng)類添加分類许饿,但是不能添加擴(kuò)展
  • 在分類中只能添加“方法”阳欲,不能增加成員變量。而擴(kuò)展中既可以添加方法也可以添加成員變量陋率。

Category中l(wèi)oad方法是什么時(shí)候調(diào)用的球化?

image

load方法在程序啟動(dòng)加載類信息的時(shí)候就會(huì)調(diào)用。它是根據(jù)函數(shù)地址直接調(diào)用的瓦糟,而不是通過消息機(jī)制的筒愚。調(diào)用順序如下:

  1. 先調(diào)用類的+load

    • 按照編譯先后順序調(diào)用(先編譯,先調(diào)用)
    • 調(diào)用子類的+load之前會(huì)先調(diào)用父類的+load
  2. 再調(diào)用分類的+load

    • 按照編譯的先后順序調(diào)用(先編譯菩浙,先調(diào)用)

load巢掺、initialize的區(qū)別

1. 調(diào)用順序

以main為分界句伶,load方法在main函數(shù)之前執(zhí)行,initialize在main函數(shù)之后執(zhí)行

2.相同點(diǎn)和不同點(diǎn)

2.1 相同點(diǎn)
  1. loadinitialize會(huì)被自動(dòng)調(diào)用陆淀,不能手動(dòng)調(diào)用它們考余。
  2. 子類實(shí)現(xiàn)了loadinitialize的話,會(huì)隱式調(diào)用父類的loadinitialize方法
  3. load和initialize方法內(nèi)部使用了鎖倔约,因此它們是線程安全的秃殉。
2.2 不同點(diǎn)

子類中沒有實(shí)現(xiàn)load方法的話,不會(huì)調(diào)用父類的load方法浸剩;而子類如果沒有實(shí)現(xiàn)initialize方法的話钾军,也會(huì)自動(dòng)調(diào)用父類的initialize方法。
load方法是在類被裝在進(jìn)來的時(shí)候就會(huì)調(diào)用绢要,initialize在第一次給某個(gè)類發(fā)送消息時(shí)調(diào)用(比如實(shí)例化一個(gè)對(duì)象)吏恭,并且只會(huì)調(diào)用一次,是懶加載模式重罪,如果這個(gè)類一直沒有使用樱哼,就不回調(diào)用到initialize方法。

3. load

在執(zhí)行l(wèi)oad方法之前剿配,會(huì)調(diào)用load_images方法搅幅,用來掃描鏡像中的+ load符號(hào),將需要調(diào)用 load 方法的類添加到一個(gè)列表中loadable_classes呼胚,在這個(gè)列表中茄唐,會(huì)先把父類加入到待加載列表,這樣保證父類在子類前調(diào)用load方法蝇更,而分類中的load方法會(huì)在類的load的方法后面加入另外一個(gè)待加載列表loadable_categories沪编,這樣保證了兩個(gè)規(guī)則:

  1. 父類先于子類調(diào)用
  2. 類先于分類調(diào)用

在掃描完load方法加入到待加載方法后,會(huì)調(diào)用call_load_methods年扩,先從loadable_classes調(diào)用類的load方法蚁廓,call_class_loads;調(diào)用完loadable_classes后會(huì)調(diào)用loadable_categories中分類的load方法厨幻,call_category_loads相嵌。

調(diào)用順序如下:

  1. 父類load先于類添加到loadable_classes列表,通過call_class_loads况脆,調(diào)用列表中的load方法平绩,這樣父類的load先于類的load執(zhí)行
  2. 當(dāng)loadable_classes為空的時(shí)候,查看loadable_classes是否為空漠另,如果不為空則調(diào)用call_category_loads加載分類中的load方法,這樣分類的load在類之后執(zhí)行

4. initialize

initialize 只會(huì)在對(duì)應(yīng)類的方法第一次被調(diào)用時(shí)跃赚,才會(huì)調(diào)用笆搓,initialize 方法是在 alloc 方法之前調(diào)用的性湿,alloc 的調(diào)用導(dǎo)致了前者的執(zhí)行。

initialize的調(diào)用棧中满败,直接調(diào)用其方法的其實(shí)是_class_initialize 這個(gè)C語言函數(shù)肤频,在這個(gè)方法中,主要是向?yàn)槌跏蓟念惏l(fā)送+initialize消息算墨,不過會(huì)強(qiáng)制父類先發(fā)送宵荒。

與 load 不同,initialize 方法調(diào)用時(shí)净嘀,所有的類都已經(jīng)加載到了內(nèi)存中报咳。

5. 使用場景

5.1 load

load一般是用來交換方法Method Swizzle,由于它是線程安全的挖藏,而且一定會(huì)調(diào)用且只會(huì)調(diào)用一次暑刃,通常在使用UrlRouter的時(shí)候注冊(cè)類的時(shí)候也在load方法中注冊(cè)

5.2 initialize

initialize方法主要用來對(duì)一些不方便在編譯期初始化的對(duì)象進(jìn)行賦值,或者說對(duì)一些靜態(tài)常量進(jìn)行初始化操作

總結(jié):

一膜眠、調(diào)用方式

1岩臣、load是根據(jù)函數(shù)地址直接調(diào)用
2、initialize是通過objc_msgSend調(diào)用

二宵膨、調(diào)用時(shí)刻

1架谎、load是runtime加載類、分類的時(shí)候調(diào)用(只會(huì)調(diào)用一次)
2辟躏、initialize是類第一次接收到消息的時(shí)候調(diào)用, 每一個(gè)類只會(huì)initialize一次(如果子類沒有實(shí)現(xiàn)initialize方法, 會(huì)調(diào)用父類的initialize方法, 所以父類的initialize方法可能會(huì)調(diào)用多次)
3谷扣、load比initialize先調(diào)用

三、使用場景

load 和 initialize 方法本質(zhì)都是做初始化的鸿脓,只不過級(jí)別或者說針對(duì)的過程不一樣抑钟。load 只會(huì)調(diào)用一次,在 main 方法調(diào)用之前做初始化野哭,比如方法交換在塔。initialize 方法針對(duì)的是 main 方法之后,而且是懶加載(類第一次接收到消息的時(shí)候調(diào)用)拨黔,使用到時(shí)才初始化蛔溃。鑒于 objc_msgSend 的機(jī)制,存在多次調(diào)用的可能篱蝇,但是可以使用代碼進(jìn)行判斷贺待。

四、load和initialize的調(diào)用順序

load調(diào)用順序
調(diào)用順序零截,需要同時(shí)滿足四種規(guī)則
先調(diào)用類的load, 在調(diào)用分類的load
先編譯的類, 優(yōu)先調(diào)用load
調(diào)用子類的load之前, 會(huì)先調(diào)用父類的load(父類 -> 子類)
沒有父子關(guān)系的類及分類之間麸塞,按Build Phases ->Complie Source 中的編譯順序
特點(diǎn):
load在父類,子類涧衙,分類之間的調(diào)用不存在覆蓋,只存在先后執(zhí)行順序
initialize調(diào)用順序
initialize調(diào)用的優(yōu)先級(jí)為 (父類分類 > 父類) > (子類分類 > 子類)
initialize在父類哪工,子類奥此,父分類,子分類之間的調(diào)用存在覆蓋【(父類與子類)(父分類與子分類)本類與分類雁比,兩兩存在覆蓋關(guān)系稚虎,兩組相互之間只會(huì)調(diào)用優(yōu)先級(jí)最高的一個(gè)】,有優(yōu)先級(jí)
特點(diǎn):
優(yōu)先級(jí):先分類后本類【分類覆蓋本類】
順序是:先父類后子類【存在先后執(zhí)行偎捎,不存在覆蓋】
通過消息機(jī)制調(diào)用, 當(dāng)子類沒有initialize方法時(shí), 會(huì)調(diào)用(父類分類>父類)的initialize方法, 所以(父類分類>父類)的initialize方法會(huì)調(diào)用多次

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蠢终,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子茴她,更是在濱河造成了極大的恐慌寻拂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件败京,死亡現(xiàn)場離奇詭異兜喻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赡麦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門朴皆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泛粹,你說我怎么就攤上這事遂铡。” “怎么了晶姊?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵扒接,是天一觀的道長。 經(jīng)常有香客問我们衙,道長钾怔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任蒙挑,我火速辦了婚禮宗侦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忆蚀。我一直安慰自己矾利,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布馋袜。 她就那樣靜靜地躺著男旗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪欣鳖。 梳的紋絲不亂的頭發(fā)上察皇,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音泽台,去河邊找鬼什荣。 笑死呀忧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溃睹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胰坟,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼因篇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起笔横,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤竞滓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吹缔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體商佑,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年厢塘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茶没。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晚碾,死狀恐怖抓半,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情格嘁,我是刑警寧澤笛求,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站糕簿,受9級(jí)特大地震影響探入,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懂诗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一蜂嗽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧响禽,春花似錦徒爹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侯繁,卻和暖如春胖喳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贮竟。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國打工丽焊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留较剃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓技健,卻偏偏與公主長得像写穴,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雌贱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

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

  • 懶加載的介紹 swift中也有懶加載的方式(蘋果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中) 和OC不同...
    猴子的救兵520閱讀 1,008評(píng)論 0 1
  • 懶加載的2個(gè)好處:延遲加載屬性(UI類型控件一般都會(huì)延遲加載)在后邊的代碼中,延遲加載的屬性,不用再強(qiáng)制解包 懶加...
    Homer1ynn閱讀 1,360評(píng)論 5 3
  • @(〓〓 iOS-Swift語法)[Swift 語法] 作者: Liwx 郵箱: 1032282633@qq.c...
    Liwx閱讀 665評(píng)論 0 0
  • 懶加載的介紹 swift中也有懶加載的方式(蘋果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中) 和OC不同...
    年輕歲月閱讀 248評(píng)論 0 0
  • 懶加載就是延時(shí)加載的意思,比方說給某個(gè)類定義個(gè)對(duì)象屬性,在用到這個(gè)屬性的時(shí)候才初始化,而且重復(fù)使用只會(huì)初始化一次,...
    Super超人閱讀 1,873評(píng)論 0 3