序
在百度三面被掛掉之后别智,沉下心來(lái)宗苍,整理構(gòu)建自己的開(kāi)發(fā)體系,方便以后查看。 金三銀四已經(jīng)降臨讳窟,為此提供了找了不少學(xué)習(xí)方向給大家吕朵,也是一些進(jìn)價(jià)方向南用,希望能幫大家快速提升自己的短板!
持續(xù)更新,敬請(qǐng)關(guān)注
本章節(jié):
- 百度三面被掛掉之后哮塞,沉下心來(lái)總結(jié)丝里,構(gòu)建自己的iOS開(kāi)發(fā)體系(上)
- 百度三面被掛掉之后匾七,沉下心來(lái)總結(jié)丘逸,構(gòu)建自己的iOS開(kāi)發(fā)體系(中)
- 百度三面被掛掉之后,沉下心來(lái)總結(jié)馏予,構(gòu)建自己的iOS開(kāi)發(fā)體系(完結(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í)面試題完整版》
下載地址:
四、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.com、www.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í)面試題完整版》
下載地址:
小編文章請(qǐng)觀看合集
- 直擊2020——iOS 面試題大全(補(bǔ)充完整版)
- “新”攜程瘦癌,阿里猪贪,騰訊iOS面試常見(jiàn)問(wèn)題合集(附答案)
- 新iOS面試題全集合(目前不斷更新)
- 新iOS開(kāi)發(fā)京東零售的面試題
- iOS開(kāi)發(fā),跳槽面試應(yīng)該注意的Swift面試題
- iOS某些大廠以及小公司的面試題讯私!
文章來(lái)源作者:強(qiáng)子ly