以大廠面試真題總結(jié),構(gòu)建自己的iOS開(kāi)發(fā)體系(中)

在百度三面被掛掉之后别智,沉下心來(lái)宗苍,整理構(gòu)建自己的開(kāi)發(fā)體系,方便以后查看。 金三銀四已經(jīng)降臨讳窟,為此提供了找了不少學(xué)習(xí)方向給大家吕朵,也是一些進(jìn)價(jià)方向南用,希望能幫大家快速提升自己的短板!

持續(xù)更新,敬請(qǐng)關(guān)注

本章節(jié):

標(biāo):不要浪費(fèi)美好的年華天梧,做自己覺(jué)得對(duì)的事情!

目錄

  • 四霞丧、Block
  • 五呢岗、Runtime
  • 六、Runloop
  • 七蛹尝、KVO
  • 八后豫、KVC
  • 九、Category
  • 十突那、網(wǎng)絡(luò)
  • 十一挫酿、UI

感謝觀看下載資料:2021年【最新iOS面試題】附答案

目錄

  • 最新 初級(jí)iOS 面試題
  • 最新 中級(jí)iOS 面試題
  • 最新 高級(jí)iOS 面試題

  • 《BAT面試資料全集》
  • 《BAT大廠常問(wèn)iOS面試題》
  • 《2021年面試真題》
  • 《iOS開(kāi)發(fā)面試題200道-面試問(wèn)答篇》
  • 《iOS開(kāi)發(fā)筆試題600道-筆試手寫篇》
  • 《iOS中級(jí)到高級(jí)面試題完整版》

下載地址:

地址:https://docs.qq.com/doc/DVU5LY1Bsb3dSZ3Nn

四、Block

17愕难、block相關(guān)
1早龟、block本質(zhì)是什么?
- block是將函數(shù)及其執(zhí)行上下文封裝起來(lái)的對(duì)象

2猫缭、關(guān)于block的截獲特性葱弟,你是否有了解?block的截獲變量特性是怎樣的猜丹?
變量捕獲機(jī)制分析:
- 對(duì)于“基本數(shù)據(jù)類型”的“局部變量”截獲其值
- 對(duì)于“對(duì)象”類型的局部變量“連同所有權(quán)修飾符”一起截獲
- 以“指針形式”截獲局部靜態(tài)變量(指針傳遞)
- 不截獲全局變量芝加、靜態(tài)全局變量(直接訪問(wèn))

改外部變量必要條件
- 將auto從棧copy到堆
原因:棧中內(nèi)存管理是由系統(tǒng)管理,出了作用域就會(huì)被回收射窒,堆中才是可以由程序員管理

3藏杖、對(duì)棧上的block進(jìn)行copy之后,假如在mrc環(huán)境下脉顿,內(nèi)存是否回泄漏蝌麸?
- copy操作之后,堆上的block沒(méi)有額外的成員變量指向它弊予,正如我們alloc對(duì)象后祥楣,沒(méi)有進(jìn)行release,造成內(nèi)存泄漏

4汉柒、面試題:請(qǐng)思考误褪,這段代碼有問(wèn)題么?
{
    __block MCBlock *blockSelf = self;
    _blk = ^int(int num){
        return num * blockSelf.var;
    }
    _blk(3);
}
- 在MRC下碾褂,不會(huì)產(chǎn)生循環(huán)引用
- 在ARC下兽间,會(huì)產(chǎn)生循環(huán)引用,造成內(nèi)存泄漏

5正塌、為什么block會(huì)產(chǎn)生循環(huán)引用嘀略?
- 如果當(dāng)前block對(duì)當(dāng)前對(duì)象的某一成員變量進(jìn)行截獲,block會(huì)對(duì)當(dāng)前對(duì)象有一個(gè)強(qiáng)引用
- 而當(dāng)前block由于當(dāng)前對(duì)象對(duì)其有一個(gè)強(qiáng)引用乓诽,產(chǎn)生了一個(gè)自循環(huán)引用的一個(gè)循環(huán)引用的問(wèn)題

6帜羊、Block不允許修改外部變量的值
原因:
- block 本質(zhì)上是一個(gè)對(duì)象,block 的花括號(hào)區(qū)域是對(duì)象內(nèi)部的一個(gè)函數(shù)鸠天,變量進(jìn)入 花括號(hào)讼育,實(shí)際就是已經(jīng)進(jìn)入了另一個(gè)函數(shù)區(qū)域---改變了作用域。
- 在幾個(gè)作用域之間進(jìn)行切換時(shí)稠集,如果不加上這樣的限制奶段,變量的可維護(hù)性將大大降低。
- 比如想在block內(nèi)聲明了一個(gè)與外部同名的變量剥纷,此時(shí)是允許呢還是不允許呢痹籍?只有加上了這樣的限制,這樣的情景才能實(shí)現(xiàn)晦鞋。

- 所以 Apple 在編譯器層面做了限制蹲缠,如果在 block 內(nèi)部試圖修改 auto 變量(無(wú)修飾符),那么直接編譯報(bào)錯(cuò)悠垛。
- 可以把編譯器的這種行為理解為:對(duì) block 內(nèi)部捕獲到的 auto 變量設(shè)置為只讀屬性---不允許直接修改吼砂。

7、如何實(shí)現(xiàn)對(duì)外部變量的捕獲鼎文?
- 將變量設(shè)置為全局變量渔肩。原理:block內(nèi)外可直接訪問(wèn)全局變量
- 加 static (放在靜態(tài)存儲(chǔ)區(qū)/全局初始化區(qū))。原理是block內(nèi)部對(duì)外部auto變量進(jìn)行指針捕獲
- 最優(yōu)解:使用__block 關(guān)鍵字

8拇惋、__block
- 將auto變量封裝為結(jié)構(gòu)體(對(duì)象)周偎,在結(jié)構(gòu)體內(nèi)部新建一個(gè)同名的auto變量
- block內(nèi)截獲該結(jié)構(gòu)體的指針
- 在block中使用自動(dòng)變量時(shí),使用指針指向的結(jié)構(gòu)體中的自動(dòng)變量

__block int var = 10;
void(^blk)(void) = ^{
    var = 20;
};
blk();

轉(zhuǎn)換后的代碼:

struct __Block_byref_var_0 {
    void *__isa;
    __Block_byref_var_0 *__forwarding;
    int __flags;
    int __size;
    int var; // 10 => 20 該結(jié)構(gòu)體持有相當(dāng)于原來(lái)自動(dòng)變量的成員變量
};

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __Block_byref_var_0 *var; // by ref
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_var_0 *_var, int flags=0) : var(_var->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};

9撑帖、block在修改NSMutableArray需不需要添加__block
- 不需要
- 當(dāng)變量是一個(gè)指針的時(shí)候蓉坎,block里只是復(fù)制了一份這個(gè)指針,兩個(gè)指針指向同一個(gè)地址胡嘿。
- 所以蛉艾,在block里面對(duì)指針指向內(nèi)容做的修改,在block外面也一樣生效。

10勿侯、block是如何捕獲局部變量的?
- block捕獲外界變量時(shí)拓瞪,在內(nèi)部會(huì)自動(dòng)生成同一個(gè)屬性來(lái)保存

11、UIView動(dòng)畫中block回調(diào)里self要不要弱引用助琐?
- 不需要祭埂,它不會(huì)造成循環(huán)引用,因?yàn)樗穷惙椒ā?- 之所以需要弱引用本身兵钮,是因?yàn)榕聦?duì)象之間產(chǎn)生循環(huán)引用蛆橡,當(dāng)前控制器不可能強(qiáng)引用一個(gè)類,所以循環(huán)無(wú)法形成掘譬。

12泰演、block里面會(huì)不會(huì)存在self為空的情況(weak strong的原理)?

__weak typeof(self) weakself = self;
[self wj_refresh_addRefreshHeader:^{
    __strong typeof(weakself) strongself = weakself;
    [strongself.dataSource reloadDataWithCompletion:nil];
}];

- 有時(shí)候weakSelf在block里在執(zhí)行reloadDataWithCompletion還存在
- 但在執(zhí)行reloadDataWithCompletion前葱轩,可能會(huì)被釋放了
- 為了保證self在block執(zhí)行過(guò)程里一直存在睦焕,對(duì)他強(qiáng)引用strongSelf

13、__block與__weak的區(qū)別
- _block不管是ARC還是MRC模式下都可以使用酿箭,可以修飾對(duì)象复亏,還可以修飾基本數(shù)據(jù)類型
- __weak只能在ARC模式下使用,也只能修飾對(duì)象(NSString)缭嫡,不能修飾基本數(shù)據(jù)類型(int)
- __block對(duì)象可以在block中被重新賦值缔御,__weak不可以。 

14妇蛀、多層block嵌套如何使用weakSelf耕突?
__weak typeof(self) weakself = self;
[self wj_refresh_addRefreshHeader:^{
    __strong typeof(weakself) strongself = weakself;
    __weak typeof(self) weakSelf2 = strongself;
    [strongself.dataSource reloadDataWithCompletion:^(BOOL result) {
        __strong typeof(self) strongSelf2 = weakSelf2;
    }];
}];

15、Masonry對(duì)于block內(nèi)部引用self會(huì)不會(huì)造成循環(huán)引用评架?
- 不會(huì)
- 這個(gè)block沒(méi)有copy眷茁,是在棧上,使用完直接釋放了纵诞,

- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

18上祈、 代理、Block利弊
- 與委托代理模式的代碼相比浙芙,用block寫出的代碼更為整潔

代理優(yōu)點(diǎn):
- 代理語(yǔ)法清晰登刺,可讀性高,易于維護(hù)
- 它減少代碼耦合性嗡呼,使事件監(jiān)聽(tīng)與事件處理分離
- 一個(gè)控制器可以實(shí)現(xiàn)多個(gè)代理纸俭,滿足自定義開(kāi)發(fā)需求,靈活性較高

代理缺點(diǎn):
- 實(shí)現(xiàn)代理的過(guò)程較繁瑣
- 跨層傳值時(shí)加大代碼的耦合性南窗,并且程序的層次結(jié)構(gòu)也變得混亂
- 當(dāng)多個(gè)對(duì)象同時(shí)傳值時(shí)不易區(qū)分揍很,導(dǎo)致代理易用性大大降低

block優(yōu)點(diǎn):
- 語(yǔ)法簡(jiǎn)潔郎楼,代碼可讀性和維護(hù)性較高
- 配合GCD優(yōu)秀的解決多線程問(wèn)題
block缺點(diǎn):
- Block中得代碼將自動(dòng)進(jìn)行一次retain操作,容易造成內(nèi)存泄漏
- Block內(nèi)默認(rèn)引用為強(qiáng)引用窒悔,容易造成循環(huán)應(yīng)用

運(yùn)行成本:
delegate運(yùn)行成本低呜袁,block的運(yùn)行成本高
- block出棧需要將使用的數(shù)據(jù)從棧內(nèi)存拷貝到堆內(nèi)存,當(dāng)然對(duì)象的話就是假引用技術(shù)蛉迹,使用完block置nil才會(huì)消除
- delegate只是保存了一個(gè)對(duì)象的指針傅寡,直接回調(diào)放妈,沒(méi)有額外的消耗北救。就像c的函數(shù)指針,只多了一個(gè)查表動(dòng)作

19芜抒、有哪些情況會(huì)出現(xiàn)內(nèi)存泄漏珍策。
- block循環(huán)引用
- delegate循環(huán)引用問(wèn)題
- NSTimer循環(huán)引用
- 地圖類處理

- 線程保活target:self

20宅倒、__weak來(lái)解決block中的循環(huán)引用攘宙,還有別的方法嗎。
- __block
- 將對(duì)象傳進(jìn)入修改


五蹭劈、Runtime

21、以下方法打印什么
@implementation Son : Father

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}

@end

這兩個(gè)都打印出來(lái)的是:Son.

- [self class] 會(huì)先在當(dāng)前類的方法列表中查找class這個(gè)方法
- [super class] 會(huì)先到父類中去查找class方法
- 兩者在找不到的時(shí)候线召,都會(huì)繼續(xù)向祖先類查詢class方法铺韧,最終到NSObject類

- NSObject中class的實(shí)現(xiàn)
- (Class)class {
    return object_getClass(self);
}

22、Runtime如何通過(guò)selector找到對(duì)應(yīng)的IMP地址缓淹?IMP和SEL關(guān)系是哈打?
- SEL:類方法的指針,相當(dāng)于一種編號(hào)讯壶,區(qū)別與IMP料仗!
- IMP:函數(shù)指針,保存了方法的地址伏蚊!

關(guān)系:SEL是通過(guò)表取對(duì)應(yīng)關(guān)系的IMP立轧,進(jìn)行方法的調(diào)用!

struct objc_method {
    SEL method_name                                      
    char *method_types                                       
    IMP method_imp                                           
}

23躏吊、Runtime的相關(guān)術(shù)語(yǔ)
SEL氛改、id、Class颜阐、Method平窘、IMP、Cache凳怨、Property

- 介紹下runtime的內(nèi)存模型(isa瑰艘、對(duì)象是鬼、類、metaclass紫新、結(jié)構(gòu)體的存儲(chǔ)信息等)
- 為什么要設(shè)計(jì)metaclass
- class_copyIvarList & class_copyPropertyList區(qū)別
- class_rw_t 和 class_ro_t 的區(qū)別

23均蜜、交互兩個(gè)方法的現(xiàn)實(shí)有什么風(fēng)險(xiǎn)?
- class_replaceMethod
- method_exchangeImplementations
- class_getInstanceMethod

個(gè)人經(jīng)驗(yàn)總結(jié):
- 當(dāng)我們寫的類沒(méi)有繼承的關(guān)系的時(shí)候芒率,倆種方法都沒(méi)什么問(wèn)題
- 當(dāng)有繼承關(guān)系又不確定方法實(shí)現(xiàn)沒(méi)實(shí)現(xiàn)囤耳,最好用class_replaceMethod方法

補(bǔ)充:在美圖秀秀面試時(shí),一個(gè)面試官問(wèn)到方法交互偶芍,我說(shuō)就是交換兩個(gè)放的IMP指針指向充择,
他問(wèn)還有么?不知道還有什么匪蟀,現(xiàn)在想起來(lái)椎麦,他應(yīng)該是想問(wèn)從isa指針到方法查找,再到根據(jù)SEL查找IMP過(guò)程吧

- 多次hook方法會(huì)存在什么問(wèn)題材彪?

TODO(待填充);??????????

24观挎、對(duì)象關(guān)聯(lián)底層數(shù)據(jù)結(jié)構(gòu)
通過(guò) runtime 的源碼得知:
- 關(guān)聯(lián)屬性并沒(méi)有添加到 category_t(分類)里邊
- 運(yùn)行時(shí)也不會(huì)合并到元類對(duì)象里邊
- 而是存儲(chǔ)在一個(gè)全局的AssociationsManager里邊

#import <objc/runtime.h>
// 添加
objc_setAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>, <#id  _Nullable value#>, <#objc_AssociationPolicy policy#>)
// 獲取
objc_getAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>)
// 移除
objc_removeAssociatedObjects(<#id  _Nonnull object#>)

- 關(guān)聯(lián)對(duì)象的應(yīng)用?系統(tǒng)如何實(shí)現(xiàn)關(guān)聯(lián)對(duì)象的
- 關(guān)聯(lián)對(duì)象的如何進(jìn)行內(nèi)存管理的段化?關(guān)聯(lián)對(duì)象如何實(shí)現(xiàn)weak屬性
- 關(guān)聯(lián)的對(duì)象嘁捷,需要在主對(duì)象dealloc的時(shí)候釋放么?

被關(guān)聯(lián)的對(duì)象的生命周期內(nèi)要比對(duì)象本身釋放晚很多显熏, 它們會(huì)在被 NSObject -dealloc 調(diào)用的 object_dispose() 方法中釋放雄嚣。

image
25、消息轉(zhuǎn)發(fā)流程佃延,向一個(gè)nil對(duì)象發(fā)送消息會(huì)怎樣
轉(zhuǎn)發(fā)過(guò)程(一定要回答出從緩存中查找)
- 消息發(fā)送
- 動(dòng)態(tài)方法解析
- 消息轉(zhuǎn)發(fā)

1现诀、消息發(fā)送過(guò)程 objc_msgSend(receiver, selector)
- 向一個(gè)對(duì)象發(fā)送消息時(shí),runtime會(huì)根據(jù)對(duì)象的isa指針找到所屬類
- 在該類的方法列表及父類方法列表中尋找方法(緩存)
- 如果在最頂層父類中依然找不到對(duì)應(yīng)方法履肃,會(huì)報(bào) unrecognized selector send to xxx

2仔沿、向一個(gè)nil對(duì)象發(fā)送消息會(huì)怎樣?
- objc_msgSend會(huì)通過(guò)判斷self來(lái)決定是否發(fā)送消息
- 如果self為nil尺棋,那么selector也會(huì)為空封锉,直接返回,不會(huì)出現(xiàn)問(wèn)題
- 但對(duì)于[NSNull null]對(duì)象發(fā)送消息時(shí)膘螟,是會(huì)crash的成福,因?yàn)镹SNull類只有一個(gè)null方法

在崩潰前有三次拯救程序崩潰的機(jī)會(huì),就是接下來(lái)的消息轉(zhuǎn)發(fā)

3荆残、消息轉(zhuǎn)發(fā)流程
TODO(待填充);??????????

26奴艾、performSelector:withObject:afterDelay: 內(nèi)部大概是怎么實(shí)現(xiàn)的,有什么注意事項(xiàng)么内斯?
內(nèi)部實(shí)現(xiàn):
- 創(chuàng)建一個(gè)定時(shí)器, 時(shí)間結(jié)束后系統(tǒng)會(huì)使用runtime通過(guò)方法名稱去方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn)并調(diào)用方法
- Selector本質(zhì)就是方法名稱

注意事項(xiàng):
- 調(diào)用performSelector:withObject:afterDelay:方法時(shí),先判斷希望調(diào)用的方法是否存在respondsToSelector:
- 這個(gè)方法是異步方法,必須在主線程調(diào)用,在子線程調(diào)用永遠(yuǎn)不會(huì)調(diào)用到想調(diào)用的方法


六蕴潦、Runloop

27像啼、RunLoop相關(guān)
什么是RunLoop?
- RunLoop 實(shí)際上是一個(gè)對(duì)象
- 這個(gè)對(duì)象在循環(huán)中用來(lái)處理程序運(yùn)行過(guò)程中出現(xiàn)的各種事件(比如說(shuō)觸摸事件潭苞、UI刷新事件忽冻、定時(shí)器事件、Selector事件)
- 從而保持程序的持續(xù)運(yùn)行
- 在沒(méi)有事件處理的時(shí)候此疹,會(huì)使線程進(jìn)入睡眠模式僧诚,從而節(jié)省 CPU 資源,提高程序性能

// 簡(jiǎn)單的理解為如下代碼
int main(int argc, char * argv[]) {        
    BOOL running = YES;
    do {
        // 執(zhí)行各種任務(wù)蝗碎,處理各種事件
        // ......
    } while (running);  // 判斷是否需要退出

    return 0;
}

- 講講runloop湖笨,項(xiàng)目中有用到么?
- runloop內(nèi)部實(shí)現(xiàn)邏輯衍菱?
- timer與runloop的關(guān)系赶么?
- 程序中添加每3秒響應(yīng)一次的NSTimer肩豁,當(dāng)拖動(dòng)tableview時(shí)timer可能無(wú)法響應(yīng)要怎么解決?
- runloop是怎么響應(yīng)用戶操作的脊串,具體流程是什么樣的?
- 說(shuō)說(shuō)runloop的幾種狀態(tài)清钥?
- runloop的mode作用是什么

int main(int argc, char * argv[]) {
    @autoreleasepool {
        int retVal = 0;
        do {
            // 睡眠中等待消息
            int message = sleep_and_wait;
            // 處理消息
            retVal = process_message(message);
        } while (retVal == 0)
        return 0;
    }
}

  • runloop內(nèi)部實(shí)現(xiàn)邏輯

    image
  • 應(yīng)用范疇

- 定時(shí)器(Timer)琼锋、PerformSelect
- GCD Async Main Queue
- 事件響應(yīng)、手勢(shì)識(shí)別祟昭、界面刷新
- 網(wǎng)絡(luò)請(qǐng)求
- AutoreleasePool

  • 基本應(yīng)用
- 保持程序的持續(xù)運(yùn)行
- 處理App中的各種事件(比如觸摸事件缕坎、定時(shí)器事件等)
- 節(jié)省CPU資源,提高程序性能:該做事時(shí)做事篡悟,該休息時(shí)休息

  • runloop和線程的關(guān)系
- 每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
- RunLoop保存在一個(gè)全局的Dictionary里谜叹,線程作為key,RunLoop作為value
- 線程剛創(chuàng)建時(shí)并沒(méi)有RunLoop對(duì)象搬葬,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建
- RunLoop會(huì)在線程結(jié)束時(shí)銷毀
- 主線程的RunLoop已經(jīng)自動(dòng)獲群衫啊(創(chuàng)建),子線程默認(rèn)沒(méi)有開(kāi)啟RunLoop

/*
 * 從字典中獲取急凰,如果沒(méi)有則直接創(chuàng)建
 */
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFSpinUnlock(&loopsLock);
if (!loop) {
    CFRunLoopRef newLoop = __CFRunLoopCreate(t);
    __CFSpinLock(&loopsLock);
    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));

    if (!loop) {
        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
        loop = newLoop;
    }

    // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
    __CFSpinUnlock(&loopsLock);
    CFRelease(newLoop);
}

28女仰、 NSTimer相關(guān)
1、NSTimer準(zhǔn)嗎抡锈?如果不準(zhǔn)的話原因是什么疾忍?如何解決?
原因:
- NSTimer的觸發(fā)時(shí)間到的時(shí)候床三,會(huì)在RunLoop中被檢測(cè)一次一罩;
- 如果在這一次的RunLoop中做了耗時(shí)的操作,會(huì)處于阻塞狀態(tài)
- 時(shí)間超過(guò)了定時(shí)器的間隔時(shí)間撇簿,觸發(fā)時(shí)間就會(huì)推遲到下一個(gè)runloop周期

解決方法:
- 在子線程中創(chuàng)建timer聂渊,在子線程中進(jìn)行定時(shí)任務(wù)的操作推汽,需要UI操作時(shí)切換回主線程進(jìn)行操作
- 使用CADisplayLink(時(shí)鐘?歧沪?歹撒?)
- 使用GCD定時(shí)器

2、使用NSTimer是如何處理循環(huán)引用的诊胞?
- 使用類方法
TODO(待填充);??????????


拓展暖夭、如何利用runloop監(jiān)控卡頓

七、KVO

29撵孤、KVO相關(guān)

KVO 的 全稱Key-Value Observing迈着,俗稱“鍵值監(jiān)聽(tīng)”,可以用于某個(gè)對(duì)象屬性值的改變

1邪码、iOS用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO裕菠?(KVO的本質(zhì)是什么)
- 利用runtimeAPI動(dòng)態(tài)生成一個(gè)子類(NSKVONotifying_XXXX),并且讓instance對(duì)象的isa指向這個(gè)全新的子類
- 當(dāng)修改instance對(duì)象的屬性時(shí)闭专,會(huì)動(dòng)用Foundation的_NSSetXXXValueAndNotify函數(shù)
- willChangeValueForKey
- 父類原來(lái)的setter方法
- didChangeValueForKey
- 內(nèi)部觸發(fā)監(jiān)聽(tīng)器(ObserveValueForKeyPath:ofObject:change:context)

2奴潘、如何手動(dòng)觸發(fā)KVO
- 手動(dòng)調(diào)用willChangeValueForKey
- 修改成員變量值
- 手動(dòng)調(diào)用didChangeValueForKey

3、直接修改成員變量會(huì)觸發(fā)KVO么
- 不會(huì)觸發(fā)KVO(原因看KVO的本質(zhì))

4影钉、object_getClass(self.person) 和 [self.person class];分別打印什么画髓?為什么?
- object_getClass(self.person); -> NSKVONotifying_MJPerson
- [self.person class];          -> MJPerson

- 原因:NSKVONotifying_MJPerson重寫底層實(shí)現(xiàn)平委,目的:隱藏動(dòng)態(tài)創(chuàng)建的類奈虾,不讓用戶感知
- (Class)class {
    return [MJPerson class];
}

// 偽代碼 Function框架
void _NSSetIntValueForKey(){
    [self willChangeValueForKey:@"age"];
    [self setAge:age];
    [self didChangeValueForKey:@"age"];
}

// 通知監(jiān)聽(tīng)器
- (void)didChangeValueForKey:(NSString *)key {
   [obser observeValueForKeyPath:key ofObject:self change:nil content:nil];
}

其他:
根據(jù)地址打印方法:p (IMP)0X1065....
類對(duì)象:  object_getClass(self.person);
原類對(duì)象:object_getClass(object_getClass(self.person));

  • 使用kvo什么時(shí)候移除監(jiān)聽(tīng)(dealloc不能移除的情況)?

八廉赔、KVC

30肉微、KVC相關(guān)

KVC的全稱是Key-Value Coding,俗稱“鍵值編碼”蜡塌,可以通過(guò)一個(gè)key來(lái)訪問(wèn)某個(gè)屬性

1碉纳、通過(guò)KVC修改屬性會(huì)出發(fā)KVO么?
- 能觸發(fā)KVO()
- KVC在修改屬性時(shí)岗照,會(huì)調(diào)用willChangeValueForKey:和didChangeValueForKey:方法村象;

2、KVC的賦值和取值過(guò)程是怎樣的攒至?原理是什么厚者?
- 見(jiàn)下圖

3、使用場(chǎng)景
- 單層字典模型轉(zhuǎn)化:[self.model setValuesForKeysWithDictionary:dict];

- 通過(guò)KVC修改未暴露的屬性:
UILabel *placeholderLabel=[self.userTextField valueForKeyPath:@"placeholderLabel"];
placeholderLabel.textColor = [UIColor redColor];

- 使用valueForKeyPath可以獲取數(shù)組中的最小值迫吐、最大值库菲、平均值、求和
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];

- 數(shù)組內(nèi)部去重
[dataArray valueForKeyPath:@"@distinctUnionOfObjects.self"]

- 數(shù)組合并(去重合并:distinctUnionOfArrays.self志膀、直接合并:unionOfArrays.self)
NSArray *temp1 = @[@3, @2, @2, @1];
NSArray *temp2 = @[@3, @4, @5];

NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@distinctUnionOfArrays.self"]);
NSLog(@"\n%@",[@[temp1, temp2] valueForKeyPath:@"@unionOfArrays.self"]);

輸出兩個(gè)數(shù)組:( 5, 1, 2, 3, 4 ), ( 3, 2, 2, 1, 3, 4, 5 )熙宇。

- 大小寫轉(zhuǎn)換(uppercaseString)及 打印字符串長(zhǎng)度同樣適用(length)
NSArray *array = @[@"name", @"w", @"aa", @"jimsa"];
NSLog(@"%@", [array valueForKeyPath:@"uppercaseString"]);
打颖钋堋:
(NAME,W,AA,JIMSA)

image
- 首先會(huì)按照setKey、_setKey的順序查找方法烫止,找到方法蒋荚,直接調(diào)用方法并賦值;
- 未找到方法馆蠕,則調(diào)用+ (BOOL)accessInstanceVariablesDirectly;
- 若accessInstanceVariablesDirectly方法返回YES期升,則按照_key、_isKey互躬、key播赁、isKey的順序查找成員變量,找到直接賦值吼渡,找不到則拋出異常容为;
- 若accessInstanceVariablesDirectly方法返回NO,則直接拋出異常寺酪;

image
- 首先會(huì)按照getKey坎背、key、isKey房维、_key的順序查找方法沼瘫,找到直接調(diào)用取值
- 若未找到,則查看+ (BOOL)accessInstanceVariablesDirectly的返回值咙俩,若返回NO,則直接拋出異常湿故;
- 若返回的YES阿趁,則按照_key、_isKey坛猪、key脖阵、isKey的順序查找成員變量,找到則取值墅茉;
- 找不到則拋出異常命黔;


九、Category

31就斤、Category相關(guān)
1悍募、Category的使用場(chǎng)合是什么?
- 將一個(gè)類拆成很多模塊(其實(shí)就是解耦洋机,將相關(guān)的功能放到一起)

2坠宴、說(shuō)說(shuō)Category的實(shí)現(xiàn)原理
- 通過(guò)runtime動(dòng)態(tài)將分類的方法合并到類對(duì)象、元類對(duì)象中
- Category編譯之后的底層結(jié)構(gòu)是 struct_category_t , 里面存儲(chǔ)著分類的對(duì)象方法绷旗、類方法喜鼓、屬性副砍、協(xié)議信息
- 在程序運(yùn)行的時(shí)候,runtime會(huì)將 Category 的數(shù)據(jù)庄岖,合并到類信息中(類對(duì)象豁翎、元類對(duì)象)

3、category和extension區(qū)別
- Extension在編譯時(shí)隅忿,就把信息合并到類信息中
- Category是在運(yùn)行時(shí)谨垃,才會(huì)將分類信息合并到類信息中
- 分類聲明的屬性,只會(huì)生成getter/setter方法聲明硼控,不會(huì)自動(dòng)生成成員變量和getter/setter方法實(shí)現(xiàn)刘陶,而擴(kuò)展會(huì)
- 分類不可用為類添加實(shí)例變量,而擴(kuò)展可以

分類的局限性:
- 無(wú)法為類添加實(shí)例變量牢撼,但可通過(guò)關(guān)聯(lián)對(duì)象進(jìn)行實(shí)現(xiàn)
- 分類的方法如果和類重名匙隔,會(huì)覆蓋原來(lái)方法的實(shí)現(xiàn)
- 多個(gè)分類的方法重名,會(huì)調(diào)用最后編譯的那個(gè)分類的實(shí)現(xiàn)

4熏版、為什么category不能添加屬性纷责?使用Runtime就可以了?
- 分類沒(méi)有自己的isa指針
- 類最開(kāi)始生成了很多基本屬性撼短,比如IvarList再膳,MethodList
- 分類只會(huì)將自己的method attach到主類,并不會(huì)影響到主類的IvarList
- 實(shí)例變量沒(méi)有setter和getter方法曲横。也沒(méi)有自己的isa指針

- 關(guān)聯(lián)對(duì)象都由AssociationsManager管理
- AssociationsManager里面是由一個(gè)靜態(tài)AssociationsHashMap來(lái)存儲(chǔ)所有的關(guān)聯(lián)對(duì)象的喂柒。
- 相當(dāng)于把所有對(duì)象的關(guān)聯(lián)對(duì)象都存在一個(gè)全局map里面。而map的的key是這個(gè)對(duì)象的指針地址
- 而這個(gè)map的value又是另外一個(gè)AssAssociationsHashMap禾嫉,里面保存了關(guān)聯(lián)對(duì)象的kv對(duì)

5灾杰、Category中有l(wèi)oad方法么?load方法什么時(shí)候調(diào)用的熙参?load方法能繼承么艳吠?
- 有
- +load方法會(huì)在runtime加載類、分類時(shí)調(diào)用孽椰;
- 每個(gè)類昭娩、分類的+load,在程序運(yùn)行過(guò)程中只調(diào)用一次

- 調(diào)用順序
- 先調(diào)用類的+load黍匾,(按照編譯先后順序栏渺,先編譯,先調(diào)用)膀捷,調(diào)用子類的+load之前會(huì)調(diào)用父類的+load
- 再調(diào)用分類的+load按照編譯先后順序調(diào)用(先編譯迈嘹,先調(diào)用)

6、test方法和load方法的本質(zhì)區(qū)別?(+load方法為什么不會(huì)被覆蓋)
- test方法是通過(guò)消息機(jī)制調(diào)用 objc_msgSend([MJPerson class], @selector(test))
- +load方法調(diào)用秀仲,直接找到內(nèi)存中的地址融痛,進(jìn)行方法調(diào)用

7、load調(diào)用順序
- +load方法會(huì)在runtime加載類神僵、分類時(shí)調(diào)用
- 每個(gè)類雁刷、分類的+load,在程序運(yùn)行過(guò)程中只調(diào)用一次

調(diào)用順序
- 先調(diào)用類的+load方法保礼,之后按照編譯先后順序調(diào)用(先編譯沛励,先調(diào)用,調(diào)用子類的+load之前會(huì)先調(diào)用父類的+load)
- 再調(diào)用分類的+load炮障,之后按照編譯先后順序調(diào)用(先編譯目派,先調(diào)用)

8、不同Category中存在同一個(gè)方法胁赢,會(huì)執(zhí)行哪個(gè)方法企蹭?如果是兩個(gè)都執(zhí)行,執(zhí)行順序是什么樣的智末?
- 根據(jù)Build Phases->Compile Sources中添加的文件順序谅摄,后面的會(huì)覆蓋前面的

9、load系馆、initialize方法的區(qū)別是什么送漠?它們?cè)赾ategory中的調(diào)用順序?以及出現(xiàn)繼承時(shí)他們之間的調(diào)用過(guò)程由蘑?
區(qū)別:
調(diào)用方式不同
- load是根據(jù)函數(shù)地址直接調(diào)用
- initialize是榮光objc_msgSend調(diào)用

調(diào)用時(shí)刻
- load是runtime加載 類/分類 的時(shí)候調(diào)用(只會(huì)調(diào)用1次)
- initialize是類第一次接收消息時(shí)調(diào)用闽寡,每一個(gè)類只會(huì)initialize一次(父類的initialize方法可能會(huì)被調(diào)用多次)

調(diào)用順序
- load:先調(diào)用類的load。先編譯的類纵穿,優(yōu)先調(diào)用load(調(diào)用子類的load之前下隧,會(huì)先調(diào)用父類的load)
- 再調(diào)用分類的load(先編譯的分類,優(yōu)先調(diào)用load)
- initialize:先初始化父類谓媒,  再初始化子類(可能最終調(diào)用的是父類的initialize方法)

10、??:
- category的方法沒(méi)有“完全替換掉”原來(lái)類已經(jīng)有的方法何乎,也就是說(shuō)如果category和原來(lái)類都有methodA句惯,那么category附加完成之后,類的方法列表里會(huì)有兩個(gè)methodA
- category的方法被放到了新方法列表的前面支救,而原來(lái)類的方法被放到了新方法列表的后面
- 這也就是我們平常所說(shuō)的category的方法會(huì)“覆蓋”掉原來(lái)類的同名方法抢野,這是因?yàn)檫\(yùn)行時(shí)在查找方法的時(shí)候是順著方法列表的順序查找的,它只要一找到對(duì)應(yīng)名字的方法各墨,就會(huì)罷休_指孤,殊不知后面可能還有一樣名字的方法。

11、為什么不能動(dòng)態(tài)添加成員變量恃轩?
- 方法和屬性并不“屬于”類實(shí)例结洼,而成員變量“屬于”類實(shí)例
- “類實(shí)例”概念,指的是一塊內(nèi)存區(qū)域叉跛,包含了isa指針和所有的成員變量松忍。
- 假如允許動(dòng)態(tài)修改類成員變量布局,已經(jīng)創(chuàng)建出的類實(shí)例就不符合類定義了筷厘,變成了無(wú)效對(duì)象鸣峭。但方法定義是在objc_class中管理的,不管如何增刪類方法酥艳,都不影響類實(shí)例的內(nèi)存布局摊溶,已經(jīng)創(chuàng)建出的類實(shí)例仍然可正常使用


十、網(wǎng)絡(luò)

32充石、TCP莫换、UDP各自的優(yōu)缺點(diǎn)及區(qū)別
TCP優(yōu)點(diǎn):( 可靠,穩(wěn)定)
- 在傳遞數(shù)據(jù)之前赫冬,會(huì)有三次握手來(lái)建立連接跷乐,
- 在數(shù)據(jù)傳遞時(shí),有確認(rèn)咬荷、窗口刽射、重傳、擁塞控制機(jī)制补鼻,
- 在數(shù)據(jù)傳完后哄啄,還會(huì)斷開(kāi)連接用來(lái)節(jié)約系統(tǒng)資源

TCP缺點(diǎn):(慢,效率低风范,占用系統(tǒng)資源高)
- TCP在傳遞數(shù)據(jù)之前咨跌,要先建連接,這會(huì)消耗時(shí)間
- 在數(shù)據(jù)傳遞時(shí)(確認(rèn)機(jī)制硼婿、重傳機(jī)制锌半、擁塞控制機(jī)制)等都會(huì)消耗大量的時(shí)間
- 因?yàn)門CP有確認(rèn)機(jī)制、三次握手機(jī)制寇漫,這些也導(dǎo)致TCP容易被人利用刊殉,實(shí)現(xiàn)DOS、DDOS州胳、CC等攻擊

UDP的優(yōu)點(diǎn):(快)
- UDP沒(méi)有TCP的握手记焊、確認(rèn)、窗口栓撞、重傳遍膜、擁塞控制等機(jī)制
- UDP是一個(gè)無(wú)狀態(tài)的傳輸協(xié)議碗硬,所以它在傳遞數(shù)據(jù)時(shí)非常快

UDP的缺點(diǎn):(不可靠瓢颅,不穩(wěn)定)
- 因?yàn)閁DP沒(méi)有TCP那些可靠的機(jī)制恩尾,在數(shù)據(jù)傳遞時(shí),如果網(wǎng)絡(luò)質(zhì)量不好惜索,就會(huì)很容易丟包

小結(jié)TCP與UDP的區(qū)別:
- TCP面向連接(如打電話要先撥號(hào)建立連接); UDP是無(wú)連接的特笋,即發(fā)送數(shù)據(jù)
- TCP提供可靠的服務(wù)。通過(guò)TCP連接傳送的數(shù)據(jù)巾兆,無(wú)差錯(cuò)猎物,不丟失,不重復(fù)角塑,且按序到達(dá)蔫磨;UDP盡最大努力交付,即不保證可靠交付
- TCP面向字節(jié)流圃伶,實(shí)際上是TCP把數(shù)據(jù)看成一連串無(wú)結(jié)構(gòu)的字節(jié)流; UDP是面向報(bào)文的
- 每一條TCP連接只能是點(diǎn)到點(diǎn)的; UDP支持一對(duì)一堤如,一對(duì)多,多對(duì)一和多對(duì)多的交互通信

33窒朋、Scoket連接和HTTP連接的區(qū)別
- HTTP協(xié)議是基于TCP連接的搀罢,是應(yīng)用層協(xié)議,主要解決如何包裝數(shù)據(jù)侥猩。Socket是對(duì)TCP/IP協(xié)議的封裝榔至,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API)欺劳,通過(guò)Socket唧取,我們才能使用TCP/IP協(xié)議。
- HTTP連接:短連接划提,客戶端向服務(wù)器發(fā)送一次請(qǐng)求枫弟,服務(wù)器響應(yīng)后連接斷開(kāi),節(jié)省資源鹏往。服務(wù)器不能主動(dòng)給客戶端響應(yīng)淡诗,iPhone主要使用類NSURLConnection
- Socket連接:長(zhǎng)連接,客戶端跟服務(wù)器端直接使用Socket進(jìn)行連接伊履,沒(méi)有規(guī)定連接后斷開(kāi)袜漩,因此客戶端和服務(wù)器段保持連接通道,雙方可以主動(dòng)發(fā)送數(shù)據(jù)

34湾碎、HTTP協(xié)議的特點(diǎn),關(guān)于HTTP請(qǐng)求GET和POST的區(qū)別
特點(diǎn):
- HTTP超文本傳輸協(xié)議奠货,是短連接介褥,是客戶端主動(dòng)發(fā)送請(qǐng)求,服務(wù)器做出響應(yīng),服務(wù)器響應(yīng)之后柔滔,鏈接斷開(kāi)
- HTTP是一個(gè)屬于應(yīng)用層面向?qū)ο蟮膮f(xié)議溢陪,HTTP有兩類報(bào)文:請(qǐng)求報(bào)文和響應(yīng)報(bào)文
- HTTP請(qǐng)求報(bào)文:一個(gè)HTTP請(qǐng)求報(bào)文由請(qǐng)求行、請(qǐng)求頭部睛廊、空行和請(qǐng)求數(shù)據(jù)4部分組成
- HTTP響應(yīng)報(bào)文:由三部分組成:狀態(tài)行形真、消息報(bào)頭、響應(yīng)正文

GET請(qǐng)求
- 參數(shù)在地址后拼接超全,不安全(因?yàn)樗袇?shù)都拼接在地址后面)
- 不適合傳輸大量數(shù)據(jù)(長(zhǎng)度有限制咆霜,為1024個(gè)字節(jié))

POST請(qǐng)求
- 參數(shù)在請(qǐng)求數(shù)據(jù)區(qū)放著,相對(duì)GET請(qǐng)求更安全
- 數(shù)據(jù)大小理論上沒(méi)有限制
- 提交的數(shù)據(jù)放置在HTTP包的包體中

35嘶朱、斷點(diǎn)續(xù)傳怎么實(shí)現(xiàn)的蛾坯?
- 斷點(diǎn)續(xù)傳主要依賴于 HTTP 頭部定義的 Range 來(lái)完成
- 有了 Range,應(yīng)用可以通過(guò) HTTP 請(qǐng)求獲取失敗的資源疏遏,從而來(lái)恢復(fù)下載該資源
- 當(dāng)然并不是所有的服務(wù)器都支持 Range脉课,但大多數(shù)服務(wù)器是可以的。Range 是以字節(jié)計(jì)算的财异,請(qǐng)求的時(shí)候不必給出結(jié)尾字節(jié)數(shù)倘零,因?yàn)檎?qǐng)求方并不一定知道資源的大小

36、網(wǎng)絡(luò)層相關(guān)面試

- 網(wǎng)絡(luò)七層協(xié)議

- Charles原理

- HTTP和HTTPS的區(qū)別呈驶?Https為什么更加安全?

- HTTPS的連接建立流程

- 解釋一下三次握手和四次揮手

- TCP分片 和 IP分片

- Cookie和Session
[網(wǎng)絡(luò)相關(guān)之Cookie和Session](http://www.reibang.com/p/5f250c621e81?utm_campaign=hugo)

37庆揩、DNS是什么俐东?DNS解析過(guò)程

域名系統(tǒng)(Domain Name System,DNS)
因特網(wǎng)上的主機(jī)订晌,可以使用多種方式標(biāo)識(shí):

  • 一種標(biāo)識(shí)方法就是用它的主機(jī)名虏辫,比如·www.baidu.comwww.google.com锈拨、gaia.cs.umass.edu
  • 另外一種方式砌庄,就是直接使用定長(zhǎng)的、有著清晰層次結(jié)構(gòu)的IP地址
1奕枢、區(qū)別:
- 主機(jī)名:方便人們記憶和接受娄昆,但長(zhǎng)度不一、沒(méi)有規(guī)律的字符串缝彬,路由器并不方便處理
- IP地址:路由器方便處理萌焰,不便于人們記憶

為了折衷這兩種方式,需要一種能進(jìn)行主機(jī)名到IP地址轉(zhuǎn)換的目錄服務(wù)谷浅,就是 域名系統(tǒng)(Domain Name System扒俯,DNS)

2奶卓、作用:
- 將用戶提供的主機(jī)名解析為IP地址

3、DNS解析過(guò)程(以www.163.com為例:)
- 打開(kāi)瀏覽器撼玄,輸入一個(gè)域名(www.163.com)夺姑。客戶端會(huì)發(fā)出一個(gè)DNS請(qǐng)求到本地DNS服務(wù)器(本地DNS服務(wù)器一般都是你的網(wǎng)絡(luò)接入服務(wù)器商提供掌猛,比如中國(guó)電信盏浙,中國(guó)移動(dòng))
- 本地DNS服務(wù)器會(huì)首先查詢它的緩存記錄,如果緩存中有此條記錄荔茬,直接返回結(jié)果废膘。如果沒(méi)有,向DNS根服務(wù)器進(jìn)行查詢兔院。
- 根DNS服務(wù)器沒(méi)有記錄具體的域名和IP地址的對(duì)應(yīng)關(guān)系殖卑,而是給出域服務(wù)器的地址,告訴他可以到域服務(wù)器上去繼續(xù)查詢
- 本地DNS服務(wù)器繼續(xù)向域服務(wù)器發(fā)出請(qǐng)求坊萝,在這個(gè)例子中孵稽,請(qǐng)求的對(duì)象是.com域服務(wù)器。
- .com域服務(wù)器收到請(qǐng)求之后十偶,也不會(huì)直接返回域名和IP地址的對(duì)應(yīng)關(guān)系菩鲜,而是告訴本地DNS服務(wù)器,你的域名的解析服務(wù)器的地址惦积。
- 最后接校,本地DNS服務(wù)器向域名的解析服務(wù)器發(fā)出請(qǐng)求,這時(shí)就能收到一個(gè)域名和IP地址對(duì)應(yīng)關(guān)系狮崩,
- 本地DNS服務(wù)器不僅要把IP地址返回給用戶電腦蛛勉,還要把這個(gè)對(duì)應(yīng)關(guān)系保存在緩存中,以備下次別的用戶查詢時(shí)睦柴,可以直接返回結(jié)果诽凌,加快網(wǎng)絡(luò)訪問(wèn)。

過(guò)程:本地服務(wù)器->根服務(wù)器->域服務(wù)器->域名解析服務(wù)器
- 整合成流程圖
TODO(待填充);??????????

十一坦敌、UI

41侣诵、Storyboard/Xib和純代碼UI相比,有哪些優(yōu)缺點(diǎn)狱窘?
storyboard/xib優(yōu)點(diǎn)
- 簡(jiǎn)單直接杜顺。直接通過(guò)拖拽和點(diǎn)選即可完成配置。
- 跳轉(zhuǎn)關(guān)系清楚

缺點(diǎn):
- 協(xié)作沖突(多人提交代碼)
- 很難做到頁(yè)面繼承和重用
- 不便于進(jìn)行模塊化管理
- 影響性能(多圖層渲染)

42蘸炸、自動(dòng)布局AutoLayout原理躬络,性能如何
戴明-iOS開(kāi)發(fā)高手課 - 03

43、說(shuō)明比較方法:layoutifNeeded搭儒、layoutSubviews洗鸵、setNeedsLayout
44膘滨、如果頁(yè)面 A 跳轉(zhuǎn)到 頁(yè)面 B,A 的 viewDidDisappear 方法和 B 的 viewDidAppear 方法哪個(gè)先調(diào)用稀拐?
- A -->viewWillDisappear
- B-->viewWillAppear
- A-->viewDidDisappear
- B-->viewDidAppear

45火邓、離屏渲染,隱式動(dòng)畫和顯式動(dòng)畫相關(guān)
??經(jīng)巢桑看到,圓角會(huì)觸發(fā)離屏渲染蜓洪。但其實(shí)這個(gè)說(shuō)法是不準(zhǔn)確的纤勒,因?yàn)閳A角觸發(fā)離屏渲染也是有條件的!

1隆檀、離屏渲染觸發(fā)條件:
- 背景色摇天、邊框、背景色+邊框恐仑,再加上圓角+裁剪泉坐,因?yàn)?contents = nil 沒(méi)有需要裁剪處理的內(nèi)容,所以不會(huì)造成離屏渲染裳仆。
- 一旦為contents設(shè)置了內(nèi)容腕让,無(wú)論是圖片、繪制內(nèi)容歧斟、有圖像信息的子視圖等纯丸,再加上圓角+裁剪,就會(huì)觸發(fā)離屏渲染静袖。

2觉鼻、在一個(gè)表內(nèi)有很多cell,每個(gè)cell上有很多個(gè)視圖,如何解決卡頓問(wèn)題?
3勾徽、切圓角一定會(huì)觸發(fā)離屏渲染嗎滑凉?

4、iOS 9及之后的系統(tǒng)版本喘帚,蘋果進(jìn)行了一些優(yōu)化
- 只設(shè)置contents或者UIImageView的image畅姊,并加上圓角+裁剪,是不會(huì)產(chǎn)生離屏渲染的吹由。
- 但如果加上了背景色若未、邊框或其他有圖像內(nèi)容的圖層,還是會(huì)產(chǎn)生離屏渲染倾鲫。
- 使用類似于UIButton的視圖的時(shí)候需要注意

46粗合、frame和bouns的區(qū)別萍嬉。什么時(shí)候frame和bouns的高寬不相等
旋轉(zhuǎn)后怎么樣

47、事件響應(yīng)過(guò)程(響應(yīng)鏈)
1隙疚、事件的傳遞 (尋找最合適的view的過(guò)程)
- 當(dāng)一個(gè)事件發(fā)生后壤追,事件會(huì)從父控件傳給子控件 (UIApplication->UIWindow->UIView->initial view)

2、事件的響應(yīng)
- 首先看initial view能否處理這個(gè)事件供屉,如果不能則會(huì)將事件傳遞給其上級(jí)視圖(inital view的superView)
- 如果上級(jí)視圖仍然無(wú)法處理則會(huì)繼續(xù)往上傳遞行冰;一直傳遞到視圖控制器view controller,首先判斷視圖控制器的根視圖view是否能處理此事件
- 如果不能則接著判斷該視圖控制器能否處理此事件伶丐,如果還是不能則繼續(xù)向上傳遞
- 一直到window悼做,如果window還是不能處理此事件則繼續(xù)交給application處理,如果最后application還是不能處理此事件則將其丟棄

3哗魂、??注意
- 事件的傳遞是從上到下(父控件到子控件)
- 事件的響應(yīng)是從下到上(順著響應(yīng)者鏈條向上傳遞:子控件到父控件)

4肛走、重要方法:
4.1、hitTest:withEvent:
- 只要事件一傳遞給一個(gè)控件,這個(gè)控件就會(huì)調(diào)用他自己的hitTest:withEvent:方法
- 尋找并返回最合適的view(能夠響應(yīng)事件的那個(gè)最合適的view)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 1.判斷自己能否接收觸摸事件
    if (self.userInteractionEnabled == NO
        || self.hidden == YES
        || self.alpha <= 0.01) {
        return nil;
    }
    // 2.判斷觸摸點(diǎn)在不在自己范圍內(nèi)
    if (![self pointInside:point withEvent:event]) {
        return nil;
    }
    // 3.從后往前遍歷自己的子控件录别,看是否有子控件更適合響應(yīng)此事件
    for(NSInteger i = self.subviews.count; i >= 0; i --) {
        UIView *childView = self.subviews[i];
        CGPoint childPoint = [self convertPoint:point toView:childView];
        UIView *fitView = [childView hitTest:childPoint withEvent:event];
        if (fitView) {
            return fitView;
        }
    }
    // 沒(méi)有找到比自己更合適的view
    return self;
}

4.2朽色、pointInside:withEvent:
- 判斷點(diǎn)在不在當(dāng)前view上(方法調(diào)用者的坐標(biāo)系上)
- 如果返回YES,代表點(diǎn)在方法調(diào)用者的坐標(biāo)系上;
- 返回NO代表點(diǎn)不在方法調(diào)用者的坐標(biāo)系上庶灿,那么方法調(diào)用者也就不能處理事件纵搁。

5、穿透
- 假設(shè)有一個(gè)黃色控件和白色控件往踢,白色空間覆蓋在黃色控件上
- 點(diǎn)擊白色view想要黃色view來(lái)響應(yīng)該事件腾誉,就是所謂的穿透

方法一、
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint yellowPoint = [self convertPoint:point toView:_yellowView];
    if ([_yellowView pointInside:yellowPoint withEvent:event]) {
        return _yellowView;
    }
    return [super hitTest:point withEvent:event];
}

方法二峻呕、
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint yellowPoint =[_yellowView convertPoint:point fromView:self];
    if ([_yellowView pointInside:yellowPoint withEvent:event]){
        return NO;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

下一章:百度三面被掛掉之后利职,沉下心來(lái)總結(jié),構(gòu)建自己的iOS開(kāi)發(fā)體系(下)

  • 最新 初級(jí)iOS 面試題
  • 最新 中級(jí)iOS 面試題
  • 最新 高級(jí)iOS 面試題

  • 《BAT面試資料全集》
  • 《BAT大廠常問(wèn)iOS面試題》
  • 《2021年面試真題》
  • 《iOS開(kāi)發(fā)面試題200道-面試問(wèn)答篇》
  • 《iOS開(kāi)發(fā)筆試題600道-筆試手寫篇》
  • 《iOS中級(jí)到高級(jí)面試題完整版》

下載地址:

地址:https://docs.qq.com/doc/DVU5LY1Bsb3dSZ3Nn

小編文章請(qǐng)觀看合集

文章來(lái)源作者:強(qiáng)子ly

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末热押,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子斤寇,更是在濱河造成了極大的恐慌桶癣,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娘锁,死亡現(xiàn)場(chǎng)離奇詭異牙寞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門间雀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悔详,“玉大人,你說(shuō)我怎么就攤上這事惹挟∏洋Γ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵匪煌,是天一觀的道長(zhǎng)责蝠。 經(jīng)常有香客問(wèn)我,道長(zhǎng)萎庭,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任齿拂,我火速辦了婚禮驳规,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘署海。我一直安慰自己吗购,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布砸狞。 她就那樣靜靜地躺著捻勉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刀森。 梳的紋絲不亂的頭發(fā)上踱启,一...
    開(kāi)封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音研底,去河邊找鬼埠偿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛榜晦,可吹牛的內(nèi)容都是我干的冠蒋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼乾胶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抖剿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起识窿,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤斩郎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后腕扶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孽拷,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年半抱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脓恕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膜宋。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖炼幔,靈堂內(nèi)的尸體忽然破棺而出秋茫,到底是詐尸還是另有隱情,我是刑警寧澤乃秀,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布肛著,位于F島的核電站,受9級(jí)特大地震影響跺讯,放射性物質(zhì)發(fā)生泄漏枢贿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一刀脏、第九天 我趴在偏房一處隱蔽的房頂上張望局荚。 院中可真熱鬧,春花似錦愈污、人聲如沸耀态。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)首装。三九已至,卻和暖如春杭跪,著一層夾襖步出監(jiān)牢的瞬間仙逻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工揍魂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桨醋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓现斋,卻偏偏與公主長(zhǎng)得像喜最,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庄蹋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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