1、category和extension的區(qū)別
- category是分類,可以為類增加自定義方法
- extension是擴(kuò)展或者延展,能為類增加屬性、成員變量和方法
- 區(qū)別呢就是category不能增加屬性和成員變量,而extension可以
- 實(shí)際項(xiàng)目中,category一般用于增加系統(tǒng)類的方法以方便使用,因?yàn)橛迷撓到y(tǒng)類的成員變量可以直接調(diào)用,還可以在內(nèi)部修改該變量,如NSString+MD5;extension一般用于擴(kuò)展自定義類的屬性或成員變量,經(jīng)常見的ViewController的.m文件中,我們增加的私有成員變量
- 如果非要給category添加成員變量也不是不可,用runtime吧
objc_setAssociatedObject
2、define 和 const常量的區(qū)別
- define宏定義在預(yù)編譯階段就進(jìn)行替換;而const常量則在編譯階段被編譯
- define不會檢測數(shù)據(jù)類型只是替換,易導(dǎo)致錯誤;const參與編譯,會檢測數(shù)據(jù)類型,較為安全
- define定義的常量在替換后運(yùn)行過程中會不斷地占用內(nèi)存,而const定義的常量存儲在數(shù)據(jù)段只有一份copy,效率更高
- define可以定義一些簡單的函數(shù)如 #define sum(a) (a+a),const不可以;
3、static關(guān)鍵字的作用
一句概括,限制變量和函數(shù)的作用域
- 函數(shù)(方法)體內(nèi) static 變量的作用范圍為該函數(shù)體,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時仍維持上次的值;
- 在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;
- 在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明 它的模塊內(nèi);
- 在類中的 static 成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
- 在類中的 static 成員函數(shù)屬于整個類所擁有,這個函數(shù)不接收 this 指針,因而只能訪問類的static 成員變量
4、 堆和棧的區(qū)別
- 從數(shù)據(jù)存儲方面講,棧用于存放基本數(shù)據(jù)類型,對象的地址等;堆用于于存放對象類型,block的copy等
- 從分配空間大小看,棧分配的空間小;堆分配的空間大
- 從管理角度看,棧由編譯器自動管理,無需我們手工控制;堆的釋放需要手動控制,容易造成內(nèi)存泄漏,因此為什么堆是需要內(nèi)存管理的。
5、OC的內(nèi)存管理機(jī)制
- ARC: Automatic Referance Count,通過retainCount引用計數(shù)來判斷對象是否應(yīng)該被釋放,每次 runloop 的時候,都會檢查自動對象的 retainCount,如果retainCount 為 0,說明該對象沒有地方需要繼續(xù)使用了,可以釋放掉了。系統(tǒng)會在編譯的時候,在代碼之間插入類似內(nèi)存管理的代碼,判斷retainCount是該+1 還是-1,合理控制retainCount的計數(shù)
- Autorelease pool:自動釋放池,程序中所有用autoreleased釋放的對象都會加入到Autorelease pool中,Autorelease pool會在線程結(jié)束的時候drain,這時Autorelease pool中的所有對象都會被release一次
- 內(nèi)存管理的問題: 盡管ARC自動引用計數(shù)幫助解決了MRC手動管理內(nèi)存的問題,但是ARC下還是會存在內(nèi)存問題,如 1、循環(huán)引用會導(dǎo)致內(nèi)存泄漏 2、Core Foundation和OC框架下的對象進(jìn)行橋接的時候,處理不當(dāng)也會引起內(nèi)存泄漏 3、Core Foundation框架下的對象對象不受ARC管理,需要開發(fā)者手動釋放,存在安全隱患
6、weak和assign的區(qū)別
- weak只能修飾引用類型,而且是弱引用類型,比如會出現(xiàn)循環(huán)引用的delegate代理屬性,delegate代理屬性也可以用assign修飾
- assign本質(zhì)上既可以修飾基本數(shù)據(jù)類型,也可以修飾引用類型,但是實(shí)際使用只用來修飾基本數(shù)據(jù)類型。
- 不同點(diǎn):weak修飾引用類型,定義了一種“非擁有關(guān)系”,會在對象釋放之后,將對象置為nil,OC中向nil對象發(fā)送消息不會引起崩潰;而assign修飾引用類型,不會在對象釋放之后置為nil,會造成野指針;
7、使用automic一定是線程安全的嗎?
不是,automic原子屬性,只是在對象的setter和getter方法中是線程安全的,例如self.arr = array 線程安全,但是[self.arr objectAtIndex:3] 就不是線程安全的,需要的話只能另外加鎖
8、 在有了自動生成屬性變量之后,@synthesize還有什么用處
- 在沒有自動生成屬性變量之前,我們必須用@systhesize才能生成對應(yīng)的setter和getter方法以及屬性變量
- 既然要用@synthesize,證明此情況下不能自動生成屬性變量,這些情況包含如下:
1、同時重寫setter和getter方法時
2、只讀變量 重寫getter方法時
3、在 @protocol 中定義屬性
4、在category中定義屬性 - 以上方法都不會自動生成屬性變量,此時就需要@systhesize name = _name
9、copy關(guān)鍵字什么時候用
- 對于不可變集合,使用copy只是對原對象的引用;對于可變集合,使用copy則是重新分配了一塊新的內(nèi)存,與原對象毫無關(guān)系
- 實(shí)際項(xiàng)目中,對于NSString、NSDictionary、NSArray都用copy,而可變集合NSMutableString、NSMutableArray使用copy,進(jìn)行一次內(nèi)容的拷貝,內(nèi)容改變不會影響原對象的數(shù)據(jù)
- block使用copy,只是MRC延續(xù)下來的習(xí)慣,在MRC中,block默認(rèn)創(chuàng)建在棧區(qū),使用copy則可以把它放到堆區(qū);在ARC中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫上copy,因?yàn)檫@樣顯示告知調(diào)用者“編譯器會自動對 block 進(jìn)行了 copy 操作”
10、對于不可變集合使用copy只是對原對象的引用,那為什么不用strong呢
- 不可變集合如NSArray用copy只是增加對象的引用,不會影響到對象的內(nèi)容,不論接收者是可變還是不可變,持有的就是原對象的一個副本
- 如果換成是用strong,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.
11、關(guān)于復(fù)制copy和mutableCopy
淺復(fù)制(shallow copy):在淺復(fù)制操作時,對于被復(fù)制對象的每一層都是指針復(fù)制。
深復(fù)制(one-level-deep copy):在深復(fù)制操作時,對于被復(fù)制對象,至少有一層是深復(fù)制。
完全復(fù)制(real-deep copy):在完全復(fù)制操作時,對于被復(fù)制對象的每一層都是對象復(fù)制。
非集合類對象的copy與mutableCopy
[不可變對象 copy] // 淺復(fù)制
[不可變對象 mutableCopy] //深復(fù)制
[可變對象 copy] //深復(fù)制
[可變對象 mutableCopy] //深復(fù)制
- 集合類對象的copy與mutableCopy
[不可變對象 copy] // 淺復(fù)制
[不可變對象 mutableCopy] //單層深復(fù)制
[可變對象 copy] //單層深復(fù)制
[可變對象 mutableCopy] //單層深復(fù)制
這里需要注意的是集合對象的內(nèi)容復(fù)制僅限于對象本身,對象元素仍然是指針復(fù)制
如:@property(nonatomic, copy)NSMutableArray *arr;這個寫法會出什么問題?
1、添加、刪除、修改數(shù)組元素的時候,程序會因?yàn)檎也坏綄?yīng)的方法而崩潰;
2、copy后返回的復(fù)制得到的不可變對象,即NSArray,NSArray類型對象不能調(diào)用NSMutableArray類型對象的方法
原因:是因?yàn)閏opy就是復(fù)制一個不可變NSArray的對象,不能對NSArray類型的對象進(jìn)行添加刪除修改
12、+(void)load; +(void)initialize;有什么用處?
- load方法
1、當(dāng)類對象被導(dǎo)入項(xiàng)目時,runtime會向每一個類對象發(fā)送load消息
2、load方法在類或者分類被引入時僅調(diào)用一次;調(diào)用順序是父類、子類、分類
3、load方法不會被類自動繼承
4、因?yàn)閘oad方法是在導(dǎo)入類的時候就被調(diào)用且一次,所以在load方法中我們可以做一些runtime的操作或者希望只執(zhí)行一次的操作 - initiallize方法
在第一次使用這個類的時候被調(diào)用一次,也就是懶加載 - 總結(jié)
1、 在OC中,runtime都會自動調(diào)用每個類的這兩個方法
2、load是在類初始加載的時候調(diào)用;initiallize是在第一次調(diào)用該類方法或者實(shí)例方法的時候被調(diào)用
3、共同點(diǎn): 只有在實(shí)現(xiàn)的前提下才會被調(diào)用; 只會調(diào)用一次\
13、addObserVer: keyPath: options: context: ,KVO的實(shí)現(xiàn)原理
- observer,觀察者;keyPath,要觀察的屬性或成員變量;options:觀察值的選項(xiàng)(新值、舊值還是都觀察);context傳入的參數(shù); KVO是基于runtime實(shí)現(xiàn)的
- 在類的某個屬性被第一次觀察的時候,系統(tǒng)會在runtime時期動態(tài)的創(chuàng)建一個該類的派生類如NSKVONotifing_Persion,在該派生類中,會重寫被觀察屬性的setter方法,該setter方法中,派生類實(shí)現(xiàn)了真正的通知機(jī)制
- OC中每個類對象都會有一個isa指針指向該類,當(dāng)該類的屬性第一次被觀察,系統(tǒng)會將該類的isa指針去指向派生類,從而屬性值改變調(diào)用setter的時候會調(diào)用派生類的setter方法
- 鍵值觀察通知依賴于NSObject 的兩個方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個被觀察屬性發(fā)生改變之前, willChangeValueForKey: 一定會被調(diào)用,這就 會記錄舊的值。而當(dāng)改變發(fā)生后,didChangeValueForKey: 會被調(diào)用,繼而 observeValueForKey:ofObject:change:context: 也會被調(diào)用。
14、 什么是block
- block是一個匿名函數(shù),也是一個代碼塊,本質(zhì)上也是OC中的對象,底層也是結(jié)構(gòu)體
- block用于回調(diào),是一個不需要立即執(zhí)行的代碼塊,可以控制執(zhí)行時機(jī)
- block屬性用copy修飾,使用中要注意避免循環(huán)引用
+block的注意點(diǎn):
1、block內(nèi)部使用外部指針會造成循環(huán)引用,需要用__weak修飾外部指針;
__weak typeOf(self) weakSelf = self;
2、block內(nèi)部如果調(diào)用了延時函數(shù)還是用弱指針會取不到該指針,因?yàn)橐呀?jīng)被銷毀了,需要在block內(nèi)再將弱指針強(qiáng)引用一下
__strong typeOf(self) strongSelf = weakSelf;
3、如果需要在block內(nèi)部修改外部棧區(qū)變量,需要用__block修飾外部變量。
15、block要用copy修飾,還是用strong
block本身是像對象一樣可以retain,和release。但是,block在創(chuàng)建的時候,它的內(nèi)存是分配在棧(stack)上,而不是在堆(heap)上。他本身的作于域是屬于創(chuàng)建時候的作用域,一旦在創(chuàng)建時候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。
使用retain也可以,但是block的retain行為默認(rèn)是用copy的行為實(shí)現(xiàn)的,
因?yàn)閎lock變量默認(rèn)是聲明為棧變量的,為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說為了block屬性聲明和實(shí)際的操作一致,最好聲明為copy。
16、KVC 和KVO
KVC,即NSKeyValueCoding兼職編碼, 一種非正式的protocol,提供了一種機(jī)制來間接訪問對象的屬性,而不是通過setter和getter方法 ,以key為例,當(dāng)然還有keyPath
1、在使用KVC去訪問屬性變量的時候,系統(tǒng)首先是查找該類的setter和getter方法;
2、如果沒有找到setter和getter方法,就會找key對應(yīng)的帶下劃線的屬性或成員變量;
3、如果沒有帶下劃線的屬性或成員變量,就找不帶下劃線的屬性或成員變量
4、如果不帶下劃線的屬性和成員變量也沒有,就會執(zhí)行setValue:(id)value forUndefinedKey或者valueForUndefinedKey,如果該類沒有實(shí)現(xiàn)對應(yīng)的方法,就會導(dǎo)致崩潰KVO,KVC是KVO的基礎(chǔ),通過鍵值路徑keypath觀察對象的某個屬性或成員變量,在KVC賦值事件發(fā)生的時候,KVO的觀察者就會發(fā)起內(nèi)部的通知機(jī)制,詳細(xì)看編號13
17、設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述
- 設(shè)計模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類型的事情
1、MVC模式: Model View Control,把模型 視圖 控制器層進(jìn)行解耦和編寫;
2、MVVM模式:Model View ViewModel,把模型 視圖 業(yè)務(wù)邏輯 層進(jìn)行解耦和編寫;
3、單例模式:通過static關(guān)鍵詞,聲明全局變量。在整個進(jìn)程運(yùn)行期間只會被賦值一次;
4、觀察者模式KVO: KVO是典型的通知模式,觀察某個屬性的狀態(tài),狀態(tài)發(fā)生變化時通知觀察者;
5、委托模式:代理+協(xié)議的組合,實(shí)現(xiàn)一對一的反向傳值操作;
6、工廠模式:通過一個類方法,批量的根據(jù)已有模板生產(chǎn)對象。
18、#import 、 #include 、 @class有什么區(qū)別 ? #import<> 和#import" " 有什么區(qū)別
-
import是OC導(dǎo)入頭文件的關(guān)鍵字,#include是C\C++導(dǎo)入頭文件的關(guān)鍵字;使用#import導(dǎo)入頭文件會自動只導(dǎo)入一次,不會重復(fù)導(dǎo)入
- @class是OC中告訴編輯器某個類的聲明,不會立即去查看這個類的實(shí)現(xiàn),只有執(zhí)行時才回去查看類的實(shí)現(xiàn),可以解決頭文件的相互包含
-
import<> 用于導(dǎo)入系統(tǒng)頭文件, #import "" 用于導(dǎo)入自定義類頭文件
19、@property的本質(zhì)是什么?ivar、getter、setter是如何生成并添加到這個類中的
- @property的本質(zhì) = ivar + getter + setter,“屬性”有兩大概念:ivar(實(shí)例變量) 、 getter+setter(存取方法)
- “屬性”(property)作為OC的一項(xiàng)特性,主要的作用就在于封裝對象的數(shù)據(jù)。OC對象通常會把其所需要的數(shù)據(jù)保存為各種實(shí)例變量。實(shí)例變量一般通過存取方法來訪問,其中,“獲取方法”(getter)用于讀取變量值,“設(shè)置方法”(setter)用于寫入變量值。
20、屬性關(guān)鍵字assign、retain、copy、nonatomic各是什么作用,在哪種情況下使用?
- assign是賦值特性,setter方法將傳入?yún)?shù)賦值給實(shí)例變量;僅設(shè)置變量時,assign用于基本數(shù)據(jù)類型;
- retain(MRC)/strong(ARC)表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retainCount會加1;
- copy表示拷貝特性。setter方法會將傳入對象復(fù)制一份,需要完全一份新的變量時
- nonatomic表示非原子特性,決定編譯器生成的setter和getter方法是否是原子操作,atomic表示多線程安全,一般使用nonatomic,效率高。
21、如何讓自己的類用copy修飾符?如何重寫帶copy關(guān)鍵字的setter?
- 需要實(shí)現(xiàn)NSCoping協(xié)議,如果自定義的對象分為可變和不可變版本,那么就要同時實(shí)現(xiàn)NSCoping和NSMutableCoping協(xié)議。
具體步驟:
1、遵循NSCoping協(xié)議
2、實(shí)現(xiàn)協(xié)議方法copyWithZone
22、ViewController的生命周期
- 按照執(zhí)行順序排列
1、initWithCoder: 通過nib文件初始化時觸發(fā)
2、awakeFromNib:nib文件被加載的時候,會發(fā)生一個awakeFromNib的消息到nib文件中的每個對象
3、loadView: 開始加載試圖控制器自導(dǎo)的view
4、viewDidLoad:試圖控制器的view加載完成
5、viewWillAppear:試圖控制器的view將要顯示在window上
6、updateViewConstraints:試圖控制器的view開始更新autoLayout約束
7、viewWillLayoutSubviews:試圖控制器的view將更新內(nèi)容視圖的位置
8、viewDidLayoutSubviews:試圖控制器的view已經(jīng)更新完使徒的位置
9、viewDidAppear:試圖控制器的view已經(jīng)展示到window上
10、viewWillDisappear:試圖控制器的view將從window上消失
11、viewWillDisappear:試圖控制器的view已經(jīng)從window上消失
23、為什么NSArray、NSDictionary、NSString經(jīng)常使用copy關(guān)鍵字
- 是因?yàn)樗麄冇袑?yīng)的可變類型NSMutableArray、NSMutableDictionary、NSMutableString,可變與不可變之間可能會進(jìn)行賦值操作,如果不可變賦值給可變對象,那可變對象修改數(shù)據(jù)可能會影響到原來的不可變對象,如果用copy的話,不管怎么賦值,都是原對象copy了一份,被賦值對象作何修改不會影響到原對象
24、談一下OC的反射機(jī)制
- class反射
1、通過類名的字符串形式實(shí)例化對象
Class class = NSClassFromString(@"Person");
Person *person = [[class alloc]init];
person.name = @"lisa";
2、將類名變?yōu)樽址?/p>
NSString *personStr = NSStringFromClass([Person class]);
- SEL反射
1、通過方法的字符串實(shí)例化方法
SEL selector = NSSelectorFromString(@"testSel");
2、方法變成字符串
SEL sel = @selector(testSel);
NSString *str = NSStringFromSelector(sel);
25、什么是謂詞?
- 謂詞就是通過NSPredicate給定的邏輯條件作為約束條件,完成對數(shù)據(jù)的篩選
NSArray *persons = @[person1,person2,person3];
//定義謂詞, 設(shè)置過濾條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age>%d",30];
//通過謂詞條件過濾數(shù)組中的元素,過濾之后返回查詢結(jié)果
NSArray *arr = [persons filteredArrayUsingPredicate:predicate];
26、isa指針問題
- isa: 是一個Class類型的指針,每個實(shí)例對象都有一個isa指針,指向其所對應(yīng)的類,而類Class里也有個isa指針,指向meteClass(元類)。元類保存了類方法的列表。當(dāng)類方法被調(diào)用時,會先從本身查找類方法的實(shí)現(xiàn),如果沒有,元類會向它父類查找該方法。需要注意的是,元類也是類,他也是對象。元類也有isa指針,指向的是根元類(root meteClass),根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)。
27、如何修改一個類的私有屬性
- KVC: setValue:屬性值 forKey:屬性名
- runtime: object_setIvar(self, 屬性名, 屬性值)
28、isKindOfClass isMemberOfClass selector
- isKindOfClass: 判斷某個對象是否屬于該類型或者繼承自該類型
- isMemberOfClass: 判斷某個對象是否是該類型
- selector 通過方法名獲取該函數(shù)在內(nèi)存中的入口
29、delegate和NSNotification的區(qū)別
- 兩者都用于傳遞消息,不同之處在于一個是一對一的,一個是一對多的
- Notification需要維護(hù)一個數(shù)組,實(shí)現(xiàn)一對多的消息的轉(zhuǎn)發(fā)
- delegate需要兩者之間建立聯(lián)系,不然沒法調(diào)用代理的方法;Notification不需要兩者建立聯(lián)系
30、iOS中常用的數(shù)據(jù)存儲方式
數(shù)據(jù)存儲有四種方案:NSUserDefault、KeyChain、file(文件存儲)、DB(數(shù)據(jù)庫存儲)
file包括:plist、Archive(歸檔)
DB包括:SQLite、FMDB、CoreData
31、iOS的沙盒目錄結(jié)構(gòu)
- Application:存放程序源文件
- Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù)。
- Library :
1、Caches:存放體積大又不需要備份的數(shù)據(jù)。(常用的緩存路徑)
2、Preference:設(shè)置目錄,iCloud會備份設(shè)置信息 - tmp:存放臨時文件,不會備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除。
32、iOS中的幾種多線程實(shí)現(xiàn)方案
- pthread:適用于Unix、Linux、Windos等系統(tǒng),跨平臺可移植,線程生命周期由程序員管理
- NSThread:面向?qū)ο螅芍苯硬僮骶€程對象,線程生命周期由程序員管理
- GCD: 充分利用設(shè)備的多核,基于C語言底層的多線程API,線程生命周期系統(tǒng)自動管理
- NSOperation:基于GCD,更加面向?qū)ο螅€程生命周期系統(tǒng)自動管理
33、簡明扼要的說一下runloop
runloop也叫做運(yùn)行循環(huán),循環(huán)內(nèi)部處理著各種事務(wù)。一個線程對應(yīng)一個runloop,基本作用就是保持線程的持續(xù)運(yùn)行,處理線程中的各種事件。通過runloop,可以讓線程在有事件的時候處理事件,沒事件的時候休息,可以節(jié)省cpu資源,提高運(yùn)行效率;
34、什么是runtime
- runtime是OC語言的重要特性,叫做運(yùn)行時,是一套底層的C語言的API,平時編寫的OC代碼,底層都是用他來實(shí)現(xiàn)的
35、Runtime實(shí)現(xiàn)的機(jī)制是什么?怎么用,一般用于干什么?
- Runtime是iOS運(yùn)行時特性實(shí)現(xiàn)的基礎(chǔ)
1、使用時需導(dǎo)入頭文件 <objc/message.h> <objc/runtime.h>
2、Runtime 運(yùn)行時機(jī)制,它是一套C語言庫。
3、實(shí)際上我們編寫的所有OC代碼,最終都是轉(zhuǎn)成了runtime庫的東西。比如:1)OC中的類轉(zhuǎn)成了Runtime庫里的結(jié)構(gòu)體等數(shù)據(jù)類型 2)方法轉(zhuǎn)成了Runtime庫里C語言函數(shù) 3)方法的調(diào)用都是Runtime庫里通過objc_msgSend,OC是動態(tài)語言,每個方法在運(yùn)行時都會動態(tài)轉(zhuǎn)化為消息發(fā)送,objc_msgSend(receiver, selector)
4、由此,可以說Runtime是OC的底層實(shí)現(xiàn),是OC的幕后執(zhí)行者
+Runtime能做什么
- Runtime庫里包含了和類、成員變量、方法相關(guān)的API。比如:
1)獲取類中的所有成員變量
2)獲取類中的所有方法
3)為類動態(tài)添加成員變量
4)為類動態(tài)添加新的方法 - 什么是 Method Swizzle(黑魔法),什么情況下會使用?
1)在沒有一個類的方法的實(shí)現(xiàn)源碼的函數(shù),想要修改它,除了通過繼承和category之外,還可以通過Method Swizzle
2)每個類都有一個方法列表,存放著selector的名字和方法實(shí)現(xiàn)的映射關(guān)系。IMP就類似于函數(shù)指針,指向方法的真正實(shí)現(xiàn)
3)在OC中調(diào)用一個方法,其實(shí)是向一個對象發(fā)送消息,查找消息的唯一依據(jù)是selector的名字。利用OC的動態(tài)特性,可以實(shí)現(xiàn)在運(yùn)行時偷換selector對應(yīng)的方法實(shí)現(xiàn)。
//根據(jù) SEL 獲取到 Method
Method method1 = class_getClassMethod(self, @selector(function1));
Method method2 = class_getClassMethod(self, @selector(function2));
//根據(jù)SEL 獲取到 方法的實(shí)現(xiàn) IMP
IMP imp = class_getMethodImplementation(self, @selector(function3));
//修改方法Method 的實(shí)現(xiàn)IMP
method_setImplementation(method1, imp);
//為類添加方法
class_addMethod(self, @selector(function3), imp, "");
//交換兩個方法的實(shí)現(xiàn),傳入的是Method,實(shí)際交換的是IMP
method_exchangeImplementations(method1, method2);
IMP imp2 = class_getMethodImplementation(self, @selector(function2));
//替換SEL對應(yīng)的實(shí)現(xiàn)IMP
class_replaceMethod(self, @selector(function3), imp2, "");
- _objc_msgForward 函數(shù)是做什么的
_objc_msgForward是 IMP 類型,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個對象發(fā)送一條消息,但它并沒有實(shí)現(xiàn)的時候,_objc_msgForward會嘗試做消息轉(zhuǎn)發(fā)。
36、HTTP協(xié)議中 POST 方法和 GET 方法有那些區(qū)別?
- GET方法用于請求數(shù)據(jù),POST方法用于提交數(shù)據(jù);
- GET請求,參數(shù)拼接在訪問路徑url上,安全性不高;POST請求參數(shù)放在請求體body里面,參數(shù)與訪問路徑url分開,較為安全;
- GET請求,訪問路徑url有長度限制,不超過255個字節(jié),而POST請求訪問路徑長度沒有限制
37、簡述APNS發(fā)送系統(tǒng)消息即推送的機(jī)制
1)應(yīng)用程序在通知中心注冊推送,由iOS系統(tǒng)向APNS請求返回設(shè)備令牌device Token;
2)應(yīng)用程序接收到APNS返回的設(shè)備令牌device Token,發(fā)送給自己的服務(wù)器;
3)服務(wù)器把需要推送的內(nèi)容和設(shè)備令牌device Token,發(fā)送給APNS
4)APNS通過device Token找到要發(fā)送的設(shè)備,iOS系統(tǒng)根據(jù)APPID把推送內(nèi)容展示
38、方法和選擇器(Selector)的區(qū)別
選擇器Selector是方法的名字,通過它可以找到方法;
方法是相對對象來說的,包含方法的名字和實(shí)現(xiàn)。
39、[self class] 和 [super class]輸出同樣的結(jié)果-當(dāng)前類Son,[super class]輸出的不是父類Father,為什么?
#import "Father.h"
@interface Son : Father
@property(nonatomic,assign)int age;
@end
@implementation Son
-(instancetype)init{
if (self = [super init]) {
NSLog(@"[self class]=====%@",[self class]); //Son
NSLog(@"[super class]=====%@",[super class]); //Son
}
return self;
}
@end
self 表示當(dāng)前這個類的對象,而 super 是一個編譯器標(biāo)示符,和 self 指向同一個消息接受者。在本例中,無論是[self class]還是[super class],接受消息者都是Son對象,但super與self不同的是,self調(diào)用class方法時,是在子類Son中查找方法,而super調(diào)用class方法時,是在父類Father中查找方法。
當(dāng)調(diào)用[self class]方法時,會轉(zhuǎn)化為objc_msgSend函數(shù),這個函數(shù)定義如下:
id objc_msgSend(id self, SEL op, ...)
這時會從當(dāng)前Son類的方法列表中查找,如果沒有,就到Father類查找,還是沒有,最后在NSObject類查找到。我們可以從NSObject.mm文件中看到- (Class)class的實(shí)現(xiàn):
- (Class)class {
return object_getClass(self);
}
所以NSLog(@"%@", NSStringFromClass([self class]));會輸出Son。
當(dāng)調(diào)用[super class]方法時,會轉(zhuǎn)化為objc_msgSendSuper,這個函數(shù)定義如下:
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
objc_msgSendSuper函數(shù)第一個參數(shù)super的數(shù)據(jù)類型是一個指向objc_super的結(jié)構(gòu)體,從message.h文件中查看它的定義:
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained Class class;
#else
__unsafe_unretained Class super_class;
#endif
/* super_class is the first class to search */
};
#endif
結(jié)構(gòu)體包含兩個成員,第一個是receiver,表示某個類的實(shí)例。第二個是super_class表示當(dāng)前類的父類。
這時首先會構(gòu)造出objc_super結(jié)構(gòu)體,這個結(jié)構(gòu)體第一個成員是self,第二個成員是(id)class_getSuperclass(objc_getClass("Son")),實(shí)際上該函數(shù)會輸出Father。然后在Father類查找class方法,查找不到,最后在NSObject查到。此時,內(nèi)部使用objc_msgSend(objc_super->receiver, @selector(class))去調(diào)用,與[self class]調(diào)用相同,所以結(jié)果還是Son。
第三方框架
- AFNetworking 底層原理分析
AFNetworking主要是對NSURLSession和NSURLConnection(iOS9.0廢棄)的封裝,其中主要有以下類:
1). AFHTTPRequestOperationManager:內(nèi)部封裝的是 NSURLConnection, 負(fù)責(zé)發(fā)送網(wǎng)絡(luò)請求, 使用最多的一個類。(3.0廢棄)
2). AFHTTPSessionManager:內(nèi)部封裝是 NSURLSession, 負(fù)責(zé)發(fā)送網(wǎng)絡(luò)請求,使用最多的一個類。
3). AFNetworkReachabilityManager:實(shí)時監(jiān)測網(wǎng)絡(luò)狀態(tài)的工具類。當(dāng)前的網(wǎng)絡(luò)環(huán)境發(fā)生改變之后,這個工具類就可以檢測到。
4). AFSecurityPolicy:網(wǎng)絡(luò)安全的工具類, 主要是針對 HTTPS 服務(wù)。
5). AFURLRequestSerialization:序列化工具類,基類。上傳的數(shù)據(jù)轉(zhuǎn)換成JSON格式
(AFJSONRequestSerializer).使用不多。
6). AFURLResponseSerialization:反序列化工具類;基類.使用比較多:
7). AFJSONResponseSerializer; JSON解析器,默認(rèn)的解析器.
8). AFHTTPResponseSerializer; 萬能解析器; JSON和XML之外的數(shù)據(jù)類型,直接返回二進(jìn)制數(shù)據(jù).對服務(wù)器返回的數(shù)據(jù)不做任何處理.
9). AFXMLParserResponseSerializer; XML解析器;
- 描述下SDWebImage里面給UIImageView加載圖片的邏輯
內(nèi)存 ——> 沙盒 ——> 網(wǎng)絡(luò)
SDWebImage 中為 UIImageView 提供了一個分類UIImageView+WebCache.h, 這個分類中有一個最常用的接口sd_setImageWithURL:placeholderImage:,會在真實(shí)圖片出現(xiàn)前會先顯示占位圖片,當(dāng)真實(shí)圖片被加載出來后再替換占位圖片。
加載圖片的過程大致如下:
1.首先會在 SDWebImageCache 中尋找圖片是否有對應(yīng)的緩存, 它會以url 作為數(shù)據(jù)的索引先在內(nèi)存中尋找是否有對應(yīng)的緩存
2.如果緩存未找到就會利用通過MD5處理過的key來繼續(xù)在磁盤中查詢對應(yīng)的數(shù)據(jù), 如果找到了, 就會把磁盤中的數(shù)據(jù)加載到內(nèi)存中,并將圖片顯示出來
3.如果在內(nèi)存和磁盤緩存中都沒有找到,就會向遠(yuǎn)程服務(wù)器發(fā)送請求,開始下載圖片
4.下載后的圖片會加入緩存中,并寫入磁盤中
5.整個獲取圖片的過程都是在子線程中執(zhí)行,獲取到圖片后回到主線程將圖片顯示出來
SDWebImage原理:
調(diào)用類別的方法:
- 從內(nèi)存(字典)中找圖片(當(dāng)這個圖片在本次使用程序的過程中已經(jīng)被加載過),找到直接使用。
- 從沙盒中找(當(dāng)這個圖片在之前使用程序的過程中被加載過),找到使用,緩存到內(nèi)存中。
- 從網(wǎng)絡(luò)上獲取,使用,緩存到內(nèi)存,緩存到沙盒。
待續(xù)。。。。。。