iOS面試之基礎(chǔ)部分

1、category和extension的區(qū)別

  • category是分類(lèi),可以為類(lèi)增加自定義方法
  • extension是擴(kuò)展或者延展,能為類(lèi)增加屬性、成員變量和方法
  • 區(qū)別呢就是category不能增加屬性和成員變量,而extension可以
  • 實(shí)際項(xiàng)目中,category一般用于增加系統(tǒng)類(lèi)的方法以方便使用,因?yàn)橛迷撓到y(tǒng)類(lèi)的成員變量可以直接調(diào)用,還可以在內(nèi)部修改該變量,如NSString+MD5;extension一般用于擴(kuò)展自定義類(lèi)的屬性或成員變量,經(jīng)常見(jiàn)的ViewController的.m文件中,我們?cè)黾拥乃接谐蓡T變量
  • 如果非要給category添加成員變量也不是不可,用runtime吧
    objc_setAssociatedObject

2、define 和 const常量的區(qū)別

  • define宏定義在預(yù)編譯階段就進(jìn)行替換;而const常量則在編譯階段被編譯
  • define不會(huì)檢測(cè)數(shù)據(jù)類(lèi)型只是替換,易導(dǎo)致錯(cuò)誤;const參與編譯,會(huì)檢測(cè)數(shù)據(jù)類(lèi)型,較為安全
  • define定義的常量在替換后運(yùn)行過(guò)程中會(huì)不斷地占用內(nèi)存,而const定義的常量存儲(chǔ)在數(shù)據(jù)段只有一份copy,效率更高
  • define可以定義一些簡(jiǎn)單的函數(shù)如 #define sum(a) (a+a),const不可以;

3、static關(guān)鍵字的作用
一句概括,限制變量和函數(shù)的作用域

  • 函數(shù)(方法)體內(nèi) static 變量的作用范圍為該函數(shù)體,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時(shí)仍維持上次的值;
  • 在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外其它函數(shù)訪問(wèn);
  • 在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明 它的模塊內(nèi);
  • 在類(lèi)中的 static 成員變量屬于整個(gè)類(lèi)所擁有,對(duì)類(lèi)的所有對(duì)象只有一份拷貝;
  • 在類(lèi)中的 static 成員函數(shù)屬于整個(gè)類(lèi)所擁有,這個(gè)函數(shù)不接收 this 指針,因而只能訪問(wèn)類(lèi)的static 成員變量

4、 堆和棧的區(qū)別

  • 從數(shù)據(jù)存儲(chǔ)方面講,棧用于存放基本數(shù)據(jù)類(lèi)型,對(duì)象的地址等;堆用于于存放對(duì)象類(lèi)型,block的copy等
  • 從分配空間大小看,棧分配的空間??;堆分配的空間大
  • 從管理角度看,棧由編譯器自動(dòng)管理,無(wú)需我們手工控制;堆的釋放需要手動(dòng)控制,容易造成內(nèi)存泄漏,因此為什么堆是需要內(nèi)存管理的。

5、OC的內(nèi)存管理機(jī)制

  • ARC: Automatic Referance Count,通過(guò)retainCount引用計(jì)數(shù)來(lái)判斷對(duì)象是否應(yīng)該被釋放,每次 runloop 的時(shí)候,都會(huì)檢查自動(dòng)對(duì)象的 retainCount,如果retainCount 為 0,說(shuō)明該對(duì)象沒(méi)有地方需要繼續(xù)使用了,可以釋放掉了。系統(tǒng)會(huì)在編譯的時(shí)候,在代碼之間插入類(lèi)似內(nèi)存管理的代碼,判斷retainCount是該+1 還是-1,合理控制retainCount的計(jì)數(shù)
  • Autorelease pool:自動(dòng)釋放池,程序中所有用autoreleased釋放的對(duì)象都會(huì)加入到Autorelease pool中,Autorelease pool會(huì)在線程結(jié)束的時(shí)候drain,這時(shí)Autorelease pool中的所有對(duì)象都會(huì)被release一次
  • 內(nèi)存管理的問(wèn)題: 盡管ARC自動(dòng)引用計(jì)數(shù)幫助解決了MRC手動(dòng)管理內(nèi)存的問(wèn)題,但是ARC下還是會(huì)存在內(nèi)存問(wèn)題,如 1、循環(huán)引用會(huì)導(dǎo)致內(nèi)存泄漏 2、Core Foundation和OC框架下的對(duì)象進(jìn)行橋接的時(shí)候,處理不當(dāng)也會(huì)引起內(nèi)存泄漏 3、Core Foundation框架下的對(duì)象對(duì)象不受ARC管理,需要開(kāi)發(fā)者手動(dòng)釋放,存在安全隱患

6、weak和assign的區(qū)別

  • weak只能修飾引用類(lèi)型,而且是弱引用類(lèi)型,比如會(huì)出現(xiàn)循環(huán)引用的delegate代理屬性,delegate代理屬性也可以用assign修飾
  • assign本質(zhì)上既可以修飾基本數(shù)據(jù)類(lèi)型,也可以修飾引用類(lèi)型,但是實(shí)際使用只用來(lái)修飾基本數(shù)據(jù)類(lèi)型。
  • 不同點(diǎn):weak修飾引用類(lèi)型,定義了一種“非擁有關(guān)系”,會(huì)在對(duì)象釋放之后,將對(duì)象置為nil,OC中向nil對(duì)象發(fā)送消息不會(huì)引起崩潰;而assign修飾引用類(lèi)型,不會(huì)在對(duì)象釋放之后置為nil,會(huì)造成野指針;

7、使用automic一定是線程安全的嗎?
不是,automic原子屬性,只是在對(duì)象的setter和getter方法中是線程安全的,例如self.arr = array 線程安全,但是[self.arr objectAtIndex:3] 就不是線程安全的,需要的話(huà)只能另外加鎖

8、 在有了自動(dòng)生成屬性變量之后,@synthesize還有什么用處

  • 在沒(méi)有自動(dòng)生成屬性變量之前,我們必須用@systhesize才能生成對(duì)應(yīng)的setter和getter方法以及屬性變量
  • 既然要用@synthesize,證明此情況下不能自動(dòng)生成屬性變量,這些情況包含如下:
    1、同時(shí)重寫(xiě)setter和getter方法時(shí)
    2、只讀變量 重寫(xiě)getter方法時(shí)
    3、在 @protocol 中定義屬性
    4、在category中定義屬性
  • 以上方法都不會(huì)自動(dòng)生成屬性變量,此時(shí)就需要@systhesize name = _name

9、copy關(guān)鍵字什么時(shí)候用

  • 對(duì)于不可變集合,使用copy只是對(duì)原對(duì)象的引用;對(duì)于可變集合,使用copy則是重新分配了一塊新的內(nèi)存,與原對(duì)象毫無(wú)關(guān)系
  • 實(shí)際項(xiàng)目中,對(duì)于NSString、NSDictionary、NSArray都用copy,而可變集合NSMutableString、NSMutableArray使用copy,進(jìn)行一次內(nèi)容的拷貝,內(nèi)容改變不會(huì)影響原對(duì)象的數(shù)據(jù)
  • block使用copy,只是MRC延續(xù)下來(lái)的習(xí)慣,在MRC中,block默認(rèn)創(chuàng)建在棧區(qū),使用copy則可以把它放到堆區(qū);在ARC中寫(xiě)不寫(xiě)都行:對(duì)于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫(xiě)上copy,因?yàn)檫@樣顯示告知調(diào)用者“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了 copy 操作”

10、對(duì)于不可變集合使用copy只是對(duì)原對(duì)象的引用,那為什么不用strong呢

  • 不可變集合如NSArray用copy只是增加對(duì)象的引用,不會(huì)影響到對(duì)象的內(nèi)容,不論接收者是可變還是不可變,持有的就是原對(duì)象的一個(gè)副本
  • 如果換成是用strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.

11、關(guān)于復(fù)制copy和mutableCopy

  • 淺復(fù)制(shallow copy):在淺復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是指針復(fù)制。

  • 深復(fù)制(one-level-deep copy):在深復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象,至少有一層是深復(fù)制。

  • 完全復(fù)制(real-deep copy):在完全復(fù)制操作時(shí),對(duì)于被復(fù)制對(duì)象的每一層都是對(duì)象復(fù)制。

  • 非集合類(lèi)對(duì)象的copy與mutableCopy

[不可變對(duì)象 copy] // 淺復(fù)制
[不可變對(duì)象 mutableCopy] //深復(fù)制
[可變對(duì)象 copy] //深復(fù)制
[可變對(duì)象 mutableCopy] //深復(fù)制
  • 集合類(lèi)對(duì)象的copy與mutableCopy
[不可變對(duì)象 copy] // 淺復(fù)制
[不可變對(duì)象 mutableCopy] //單層深復(fù)制
[可變對(duì)象 copy] //單層深復(fù)制
[可變對(duì)象 mutableCopy] //單層深復(fù)制
  • 這里需要注意的是集合對(duì)象的內(nèi)容復(fù)制僅限于對(duì)象本身,對(duì)象元素仍然是指針復(fù)制

  • 如:@property(nonatomic, copy)NSMutableArray *arr;這個(gè)寫(xiě)法會(huì)出什么問(wèn)題?
    1、添加、刪除、修改數(shù)組元素的時(shí)候,程序會(huì)因?yàn)檎也坏綄?duì)應(yīng)的方法而崩潰;
    2、copy后返回的復(fù)制得到的不可變對(duì)象,即NSArray,NSArray類(lèi)型對(duì)象不能調(diào)用NSMutableArray類(lèi)型對(duì)象的方法
    原因:是因?yàn)閏opy就是復(fù)制一個(gè)不可變NSArray的對(duì)象,不能對(duì)NSArray類(lèi)型的對(duì)象進(jìn)行添加刪除修改

12、+(void)load; +(void)initialize;有什么用處?

  • load方法
    1、當(dāng)類(lèi)對(duì)象被導(dǎo)入項(xiàng)目時(shí),runtime會(huì)向每一個(gè)類(lèi)對(duì)象發(fā)送load消息
    2、load方法在類(lèi)或者分類(lèi)被引入時(shí)僅調(diào)用一次;調(diào)用順序是父類(lèi)、子類(lèi)、分類(lèi)
    3、load方法不會(huì)被類(lèi)自動(dòng)繼承
    4、因?yàn)閘oad方法是在導(dǎo)入類(lèi)的時(shí)候就被調(diào)用且一次,所以在load方法中我們可以做一些runtime的操作或者希望只執(zhí)行一次的操作
  • initiallize方法
    在第一次使用這個(gè)類(lèi)的時(shí)候被調(diào)用一次,也就是懶加載
  • 總結(jié)
    1、 在OC中,runtime都會(huì)自動(dòng)調(diào)用每個(gè)類(lèi)的這兩個(gè)方法
    2、load是在類(lèi)初始加載的時(shí)候調(diào)用;initiallize是在第一次調(diào)用該類(lèi)方法或者實(shí)例方法的時(shí)候被調(diào)用
    3、共同點(diǎn): 只有在實(shí)現(xiàn)的前提下才會(huì)被調(diào)用; 只會(huì)調(diào)用一次\

13、addObserVer: keyPath: options: context: ,KVO的實(shí)現(xiàn)原理

  • observer,觀察者;keyPath,要觀察的屬性或成員變量;options:觀察值的選項(xiàng)(新值、舊值還是都觀察);context傳入的參數(shù); KVO是基于runtime實(shí)現(xiàn)的
  • 在類(lèi)的某個(gè)屬性被第一次觀察的時(shí)候,系統(tǒng)會(huì)在runtime時(shí)期動(dòng)態(tài)的創(chuàng)建一個(gè)該類(lèi)的派生類(lèi)如NSKVONotifing_Persion,在該派生類(lèi)中,會(huì)重寫(xiě)被觀察屬性的setter方法,該setter方法中,派生類(lèi)實(shí)現(xiàn)了真正的通知機(jī)制
  • OC中每個(gè)類(lèi)對(duì)象都會(huì)有一個(gè)isa指針指向該類(lèi),當(dāng)該類(lèi)的屬性第一次被觀察,系統(tǒng)會(huì)將該類(lèi)的isa指針去指向派生類(lèi),從而屬性值改變調(diào)用setter的時(shí)候會(huì)調(diào)用派生類(lèi)的setter方法
  • 鍵值觀察通知依賴(lài)于NSObject 的兩個(gè)方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個(gè)被觀察屬性發(fā)生改變之前, willChangeValueForKey: 一定會(huì)被調(diào)用,這就 會(huì)記錄舊的值。而當(dāng)改變發(fā)生后,didChangeValueForKey: 會(huì)被調(diào)用,繼而 observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用。

14、 什么是block

  • block是一個(gè)匿名函數(shù),也是一個(gè)代碼塊,本質(zhì)上也是OC中的對(duì)象,底層也是結(jié)構(gòu)體
  • block用于回調(diào),是一個(gè)不需要立即執(zhí)行的代碼塊,可以控制執(zhí)行時(shí)機(jī)
  • block屬性用copy修飾,使用中要注意避免循環(huán)引用
    +block的注意點(diǎn):
    1、block內(nèi)部使用外部指針會(huì)造成循環(huán)引用,需要用__weak修飾外部指針;
    __weak typeOf(self) weakSelf = self;
    2、block內(nèi)部如果調(diào)用了延時(shí)函數(shù)還是用弱指針會(huì)取不到該指針,因?yàn)橐呀?jīng)被銷(xiāo)毀了,需要在block內(nèi)再將弱指針強(qiáng)引用一下
    __strong typeOf(self) strongSelf = weakSelf;
    3、如果需要在block內(nèi)部修改外部棧區(qū)變量,需要用__block修飾外部變量。

15、block要用copy修飾,還是用strong
block本身是像對(duì)象一樣可以retain,和release。但是,block在創(chuàng)建的時(shí)候,它的內(nèi)存是分配在棧(stack)上,而不是在堆(heap)上。他本身的作于域是屬于創(chuàng)建時(shí)候的作用域,一旦在創(chuàng)建時(shí)候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。
使用retain也可以,但是block的retain行為默認(rèn)是用copy的行為實(shí)現(xiàn)的,
因?yàn)閎lock變量默認(rèn)是聲明為棧變量的,為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說(shuō)為了block屬性聲明和實(shí)際的操作一致,最好聲明為copy。

16、KVC 和KVO

  • KVC,即NSKeyValueCoding兼職編碼, 一種非正式的protocol,提供了一種機(jī)制來(lái)間接訪問(wèn)對(duì)象的屬性,而不是通過(guò)setter和getter方法 ,以key為例,當(dāng)然還有keyPath
    1、在使用KVC去訪問(wèn)屬性變量的時(shí)候,系統(tǒng)首先是查找該類(lèi)的setter和getter方法;
    2、如果沒(méi)有找到setter和getter方法,就會(huì)找key對(duì)應(yīng)的帶下劃線的屬性或成員變量;
    3、如果沒(méi)有帶下劃線的屬性或成員變量,就找不帶下劃線的屬性或成員變量
    4、如果不帶下劃線的屬性和成員變量也沒(méi)有,就會(huì)執(zhí)行setValue:(id)value forUndefinedKey或者valueForUndefinedKey,如果該類(lèi)沒(méi)有實(shí)現(xiàn)對(duì)應(yīng)的方法,就會(huì)導(dǎo)致崩潰

  • KVO,KVC是KVO的基礎(chǔ),通過(guò)鍵值路徑keypath觀察對(duì)象的某個(gè)屬性或成員變量,在KVC賦值事件發(fā)生的時(shí)候,KVO的觀察者就會(huì)發(fā)起內(nèi)部的通知機(jī)制,詳細(xì)看編號(hào)13

17、設(shè)計(jì)模式是什么? 你知道哪些設(shè)計(jì)模式,并簡(jiǎn)要敘述

  • 設(shè)計(jì)模式是一種編碼經(jīng)驗(yàn),就是用比較成熟的邏輯去處理某一種類(lèi)型的事情
    1、MVC模式: Model View Control,把模型 視圖 控制器層進(jìn)行解耦和編寫(xiě);
    2、MVVM模式:Model View ViewModel,把模型 視圖 業(yè)務(wù)邏輯 層進(jìn)行解耦和編寫(xiě);
    3、單例模式:通過(guò)static關(guān)鍵詞,聲明全局變量。在整個(gè)進(jìn)程運(yùn)行期間只會(huì)被賦值一次;
    4、觀察者模式KVO: KVO是典型的通知模式,觀察某個(gè)屬性的狀態(tài),狀態(tài)發(fā)生變化時(shí)通知觀察者;
    5、委托模式:代理+協(xié)議的組合,實(shí)現(xiàn)一對(duì)一的反向傳值操作;
    6、工廠模式:通過(guò)一個(gè)類(lèi)方法,批量的根據(jù)已有模板生產(chǎn)對(duì)象。

18、#import 、 #include 、 @class有什么區(qū)別 ? #import<> 和#import" " 有什么區(qū)別

  • import是OC導(dǎo)入頭文件的關(guān)鍵字,#include是C\C++導(dǎo)入頭文件的關(guān)鍵字;使用#import導(dǎo)入頭文件會(huì)自動(dòng)只導(dǎo)入一次,不會(huì)重復(fù)導(dǎo)入

  • @class是OC中告訴編輯器某個(gè)類(lèi)的聲明,不會(huì)立即去查看這個(gè)類(lèi)的實(shí)現(xiàn),只有執(zhí)行時(shí)才回去查看類(lèi)的實(shí)現(xiàn),可以解決頭文件的相互包含
  • import<> 用于導(dǎo)入系統(tǒng)頭文件, #import "" 用于導(dǎo)入自定義類(lèi)頭文件

19、@property的本質(zhì)是什么?ivar、getter、setter是如何生成并添加到這個(gè)類(lèi)中的

  • @property的本質(zhì) = ivar + getter + setter,“屬性”有兩大概念:ivar(實(shí)例變量) 、 getter+setter(存取方法)
  • “屬性”(property)作為OC的一項(xiàng)特性,主要的作用就在于封裝對(duì)象的數(shù)據(jù)。OC對(duì)象通常會(huì)把其所需要的數(shù)據(jù)保存為各種實(shí)例變量。實(shí)例變量一般通過(guò)存取方法來(lái)訪問(wèn),其中,“獲取方法”(getter)用于讀取變量值,“設(shè)置方法”(setter)用于寫(xiě)入變量值。

20、屬性關(guān)鍵字assign、retain、copy、nonatomic各是什么作用,在哪種情況下使用?

  • assign是賦值特性,setter方法將傳入?yún)?shù)賦值給實(shí)例變量;僅設(shè)置變量時(shí),assign用于基本數(shù)據(jù)類(lèi)型;
  • retain(MRC)/strong(ARC)表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retainCount會(huì)加1;
  • copy表示拷貝特性。setter方法會(huì)將傳入對(duì)象復(fù)制一份,需要完全一份新的變量時(shí)
  • nonatomic表示非原子特性,決定編譯器生成的setter和getter方法是否是原子操作,atomic表示多線程安全,一般使用nonatomic,效率高。

21、如何讓自己的類(lèi)用copy修飾符?如何重寫(xiě)帶copy關(guān)鍵字的setter?

  • 需要實(shí)現(xiàn)NSCoping協(xié)議,如果自定義的對(duì)象分為可變和不可變版本,那么就要同時(shí)實(shí)現(xiàn)NSCoping和NSMutableCoping協(xié)議。
    具體步驟:
    1、遵循NSCoping協(xié)議
    2、實(shí)現(xiàn)協(xié)議方法copyWithZone

22、ViewController的生命周期

  • 按照?qǐng)?zhí)行順序排列
    1、initWithCoder: 通過(guò)nib文件初始化時(shí)觸發(fā)
    2、awakeFromNib:nib文件被加載的時(shí)候,會(huì)發(fā)生一個(gè)awakeFromNib的消息到nib文件中的每個(gè)對(duì)象
    3、loadView: 開(kāi)始加載試圖控制器自導(dǎo)的view
    4、viewDidLoad:試圖控制器的view加載完成
    5、viewWillAppear:試圖控制器的view將要顯示在window上
    6、updateViewConstraints:試圖控制器的view開(kāi)始更新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)樗麄冇袑?duì)應(yīng)的可變類(lèi)型NSMutableArray、NSMutableDictionary、NSMutableString,可變與不可變之間可能會(huì)進(jìn)行賦值操作,如果不可變賦值給可變對(duì)象,那可變對(duì)象修改數(shù)據(jù)可能會(huì)影響到原來(lái)的不可變對(duì)象,如果用copy的話(huà),不管怎么賦值,都是原對(duì)象copy了一份,被賦值對(duì)象作何修改不會(huì)影響到原對(duì)象

24、談一下OC的反射機(jī)制

  • class反射
    1、通過(guò)類(lèi)名的字符串形式實(shí)例化對(duì)象
    Class class = NSClassFromString(@"Person");
    Person *person = [[class alloc]init];
    person.name = @"lisa";

2、將類(lèi)名變?yōu)樽址?/p>

    NSString *personStr = NSStringFromClass([Person class]);
  • SEL反射
    1、通過(guò)方法的字符串實(shí)例化方法
    SEL  selector = NSSelectorFromString(@"testSel");

2、方法變成字符串

    SEL sel = @selector(testSel);
    NSString *str = NSStringFromSelector(sel);

25、什么是謂詞?

  • 謂詞就是通過(guò)NSPredicate給定的邏輯條件作為約束條件,完成對(duì)數(shù)據(jù)的篩選
    NSArray *persons = @[person1,person2,person3];
    //定義謂詞, 設(shè)置過(guò)濾條件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age>%d",30];
    //通過(guò)謂詞條件過(guò)濾數(shù)組中的元素,過(guò)濾之后返回查詢(xún)結(jié)果
    NSArray *arr = [persons filteredArrayUsingPredicate:predicate];

26、isa指針問(wèn)題

  • isa: 是一個(gè)Class類(lèi)型的指針,每個(gè)實(shí)例對(duì)象都有一個(gè)isa指針,指向其所對(duì)應(yīng)的類(lèi),而類(lèi)Class里也有個(gè)isa指針,指向meteClass(元類(lèi))。元類(lèi)保存了類(lèi)方法的列表。當(dāng)類(lèi)方法被調(diào)用時(shí),會(huì)先從本身查找類(lèi)方法的實(shí)現(xiàn),如果沒(méi)有,元類(lèi)會(huì)向它父類(lèi)查找該方法。需要注意的是,元類(lèi)也是類(lèi),他也是對(duì)象。元類(lèi)也有isa指針,指向的是根元類(lèi)(root meteClass),根元類(lèi)的isa指針指向本身,這樣形成了一個(gè)封閉的內(nèi)循環(huán)。

27、如何修改一個(gè)類(lèi)的私有屬性

  • KVC: setValue:屬性值 forKey:屬性名
  • runtime: object_setIvar(self, 屬性名, 屬性值)

28、isKindOfClass isMemberOfClass selector

  • isKindOfClass: 判斷某個(gè)對(duì)象是否屬于該類(lèi)型或者繼承自該類(lèi)型
  • isMemberOfClass: 判斷某個(gè)對(duì)象是否是該類(lèi)型
  • selector 通過(guò)方法名獲取該函數(shù)在內(nèi)存中的入口

29、delegate和NSNotification的區(qū)別

  • 兩者都用于傳遞消息,不同之處在于一個(gè)是一對(duì)一的,一個(gè)是一對(duì)多的
  • Notification需要維護(hù)一個(gè)數(shù)組,實(shí)現(xiàn)一對(duì)多的消息的轉(zhuǎn)發(fā)
  • delegate需要兩者之間建立聯(lián)系,不然沒(méi)法調(diào)用代理的方法;Notification不需要兩者建立聯(lián)系

30、iOS中常用的數(shù)據(jù)存儲(chǔ)方式
數(shù)據(jù)存儲(chǔ)有四種方案:NSUserDefault、KeyChain、file(文件存儲(chǔ))、DB(數(shù)據(jù)庫(kù)存儲(chǔ))
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會(huì)備份設(shè)置信息
  • tmp:存放臨時(shí)文件,不會(huì)備份,而且這個(gè)文件下的數(shù)據(jù)有可能隨時(shí)被清除。

32、iOS中的幾種多線程實(shí)現(xiàn)方案

  • pthread:適用于Unix、Linux、Windos等系統(tǒng),跨平臺(tái)可移植,線程生命周期由程序員管理
  • NSThread:面向?qū)ο螅芍苯硬僮骶€程對(duì)象,線程生命周期由程序員管理
  • GCD: 充分利用設(shè)備的多核,基于C語(yǔ)言底層的多線程API,線程生命周期系統(tǒng)自動(dòng)管理
  • NSOperation:基于GCD,更加面向?qū)ο螅€程生命周期系統(tǒng)自動(dòng)管理

33、簡(jiǎn)明扼要的說(shuō)一下runloop
runloop也叫做運(yùn)行循環(huán),循環(huán)內(nèi)部處理著各種事務(wù)。一個(gè)線程對(duì)應(yīng)一個(gè)runloop,基本作用就是保持線程的持續(xù)運(yùn)行,處理線程中的各種事件。通過(guò)runloop,可以讓線程在有事件的時(shí)候處理事件,沒(méi)事件的時(shí)候休息,可以節(jié)省cpu資源,提高運(yùn)行效率;

34、什么是runtime

  • runtime是OC語(yǔ)言的重要特性,叫做運(yùn)行時(shí),是一套底層的C語(yǔ)言的API,平時(shí)編寫(xiě)的OC代碼,底層都是用他來(lái)實(shí)現(xiàn)的

35、Runtime實(shí)現(xiàn)的機(jī)制是什么?怎么用,一般用于干什么?

  • Runtime是iOS運(yùn)行時(shí)特性實(shí)現(xiàn)的基礎(chǔ)
    1、使用時(shí)需導(dǎo)入頭文件 <objc/message.h> <objc/runtime.h>
    2、Runtime 運(yùn)行時(shí)機(jī)制,它是一套C語(yǔ)言庫(kù)。
    3、實(shí)際上我們編寫(xiě)的所有OC代碼,最終都是轉(zhuǎn)成了runtime庫(kù)的東西。比如:1)OC中的類(lèi)轉(zhuǎn)成了Runtime庫(kù)里的結(jié)構(gòu)體等數(shù)據(jù)類(lèi)型 2)方法轉(zhuǎn)成了Runtime庫(kù)里C語(yǔ)言函數(shù) 3)方法的調(diào)用都是Runtime庫(kù)里通過(guò)objc_msgSend,OC是動(dòng)態(tài)語(yǔ)言,每個(gè)方法在運(yùn)行時(shí)都會(huì)動(dòng)態(tài)轉(zhuǎn)化為消息發(fā)送,objc_msgSend(receiver, selector)
    4、由此,可以說(shuō)Runtime是OC的底層實(shí)現(xiàn),是OC的幕后執(zhí)行者

+Runtime能做什么

  • Runtime庫(kù)里包含了和類(lèi)、成員變量、方法相關(guān)的API。比如:
    1)獲取類(lèi)中的所有成員變量
    2)獲取類(lèi)中的所有方法
    3)為類(lèi)動(dòng)態(tài)添加成員變量
    4)為類(lèi)動(dòng)態(tài)添加新的方法
  • 什么是 Method Swizzle(黑魔法),什么情況下會(huì)使用?
    1)在沒(méi)有一個(gè)類(lèi)的方法的實(shí)現(xiàn)源碼的函數(shù),想要修改它,除了通過(guò)繼承和category之外,還可以通過(guò)Method Swizzle
    2)每個(gè)類(lèi)都有一個(gè)方法列表,存放著selector的名字和方法實(shí)現(xiàn)的映射關(guān)系。IMP就類(lèi)似于函數(shù)指針,指向方法的真正實(shí)現(xiàn)
    3)在OC中調(diào)用一個(gè)方法,其實(shí)是向一個(gè)對(duì)象發(fā)送消息,查找消息的唯一依據(jù)是selector的名字。利用OC的動(dòng)態(tài)特性,可以實(shí)現(xiàn)在運(yùn)行時(shí)偷換selector對(duì)應(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);
    
    //為類(lèi)添加方法
    class_addMethod(self, @selector(function3), imp, "");
    
    //交換兩個(gè)方法的實(shí)現(xiàn),傳入的是Method,實(shí)際交換的是IMP
    method_exchangeImplementations(method1, method2);
    
    IMP imp2 = class_getMethodImplementation(self, @selector(function2));
    //替換SEL對(duì)應(yīng)的實(shí)現(xiàn)IMP
    class_replaceMethod(self, @selector(function3), imp2, "");
  • _objc_msgForward 函數(shù)是做什么的
    _objc_msgForward是 IMP 類(lèi)型,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個(gè)對(duì)象發(fā)送一條消息,但它并沒(méi)有實(shí)現(xiàn)的時(shí)候,_objc_msgForward會(huì)嘗試做消息轉(zhuǎn)發(fā)。

36、HTTP協(xié)議中 POST 方法和 GET 方法有那些區(qū)別?

  • GET方法用于請(qǐng)求數(shù)據(jù),POST方法用于提交數(shù)據(jù);
  • GET請(qǐng)求,參數(shù)拼接在訪問(wèn)路徑url上,安全性不高;POST請(qǐng)求參數(shù)放在請(qǐng)求體body里面,參數(shù)與訪問(wèn)路徑url分開(kāi),較為安全;
  • GET請(qǐng)求,訪問(wèn)路徑url有長(zhǎng)度限制,不超過(guò)255個(gè)字節(jié),而POST請(qǐng)求訪問(wèn)路徑長(zhǎng)度沒(méi)有限制

37、簡(jiǎn)述APNS發(fā)送系統(tǒng)消息即推送的機(jī)制
1)應(yīng)用程序在通知中心注冊(cè)推送,由iOS系統(tǒng)向APNS請(qǐng)求返回設(shè)備令牌device Token;
2)應(yīng)用程序接收到APNS返回的設(shè)備令牌device Token,發(fā)送給自己的服務(wù)器;
3)服務(wù)器把需要推送的內(nèi)容和設(shè)備令牌device Token,發(fā)送給APNS
4)APNS通過(guò)device Token找到要發(fā)送的設(shè)備,iOS系統(tǒng)根據(jù)APPID把推送內(nèi)容展示

38、方法和選擇器(Selector)的區(qū)別
選擇器Selector是方法的名字,通過(guò)它可以找到方法;
方法是相對(duì)對(duì)象來(lái)說(shuō)的,包含方法的名字和實(shí)現(xiàn)。

39、[self class] 和 [super class]輸出同樣的結(jié)果-當(dāng)前類(lèi)Son,[super class]輸出的不是父類(lèi)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)前這個(gè)類(lèi)的對(duì)象,而 super 是一個(gè)編譯器標(biāo)示符,和 self 指向同一個(gè)消息接受者。在本例中,無(wú)論是[self class]還是[super class],接受消息者都是Son對(duì)象,但super與self不同的是,self調(diào)用class方法時(shí),是在子類(lèi)Son中查找方法,而super調(diào)用class方法時(shí),是在父類(lèi)Father中查找方法。

當(dāng)調(diào)用[self class]方法時(shí),會(huì)轉(zhuǎn)化為objc_msgSend函數(shù),這個(gè)函數(shù)定義如下:

id objc_msgSend(id self, SEL op, ...)

這時(shí)會(huì)從當(dāng)前Son類(lèi)的方法列表中查找,如果沒(méi)有,就到Father類(lèi)查找,還是沒(méi)有,最后在NSObject類(lèi)查找到。我們可以從NSObject.mm文件中看到- (Class)class的實(shí)現(xiàn):

- (Class)class {
    return object_getClass(self);
}

所以NSLog(@"%@", NSStringFromClass([self class]));會(huì)輸出Son。

當(dāng)調(diào)用[super class]方法時(shí),會(huì)轉(zhuǎn)化為objc_msgSendSuper,這個(gè)函數(shù)定義如下:

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)

objc_msgSendSuper函數(shù)第一個(gè)參數(shù)super的數(shù)據(jù)類(lèi)型是一個(gè)指向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)體包含兩個(gè)成員,第一個(gè)是receiver,表示某個(gè)類(lèi)的實(shí)例。第二個(gè)是super_class表示當(dāng)前類(lèi)的父類(lèi)。

這時(shí)首先會(huì)構(gòu)造出objc_super結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體第一個(gè)成員是self,第二個(gè)成員是(id)class_getSuperclass(objc_getClass("Son")),實(shí)際上該函數(shù)會(huì)輸出Father。然后在Father類(lèi)查找class方法,查找不到,最后在NSObject查到。此時(shí),內(nèi)部使用objc_msgSend(objc_super->receiver, @selector(class))去調(diào)用,與[self class]調(diào)用相同,所以結(jié)果還是Son。

第三方框架
  • AFNetworking 底層原理分析

AFNetworking主要是對(duì)NSURLSession和NSURLConnection(iOS9.0廢棄)的封裝,其中主要有以下類(lèi):
1). AFHTTPRequestOperationManager:內(nèi)部封裝的是 NSURLConnection, 負(fù)責(zé)發(fā)送網(wǎng)絡(luò)請(qǐng)求, 使用最多的一個(gè)類(lèi)。(3.0廢棄)
2). AFHTTPSessionManager:內(nèi)部封裝是 NSURLSession, 負(fù)責(zé)發(fā)送網(wǎng)絡(luò)請(qǐng)求,使用最多的一個(gè)類(lèi)。
3). AFNetworkReachabilityManager:實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài)的工具類(lèi)。當(dāng)前的網(wǎng)絡(luò)環(huán)境發(fā)生改變之后,這個(gè)工具類(lèi)就可以檢測(cè)到。
4). AFSecurityPolicy:網(wǎng)絡(luò)安全的工具類(lèi), 主要是針對(duì) HTTPS 服務(wù)。
5). AFURLRequestSerialization:序列化工具類(lèi),基類(lèi)。上傳的數(shù)據(jù)轉(zhuǎn)換成JSON格式
(AFJSONRequestSerializer).使用不多。
6). AFURLResponseSerialization:反序列化工具類(lèi);基類(lèi).使用比較多:
7). AFJSONResponseSerializer; JSON解析器,默認(rèn)的解析器.
8). AFHTTPResponseSerializer; 萬(wàn)能解析器; JSON和XML之外的數(shù)據(jù)類(lèi)型,直接返回二進(jìn)制數(shù)據(jù).對(duì)服務(wù)器返回的數(shù)據(jù)不做任何處理.
9). AFXMLParserResponseSerializer; XML解析器;

  • 描述下SDWebImage里面給UIImageView加載圖片的邏輯
    內(nèi)存 ——> 沙盒 ——> 網(wǎng)絡(luò)
    SDWebImage 中為 UIImageView 提供了一個(gè)分類(lèi)UIImageView+WebCache.h, 這個(gè)分類(lèi)中有一個(gè)最常用的接口sd_setImageWithURL:placeholderImage:,會(huì)在真實(shí)圖片出現(xiàn)前會(huì)先顯示占位圖片,當(dāng)真實(shí)圖片被加載出來(lái)后再替換占位圖片。

加載圖片的過(guò)程大致如下:
1.首先會(huì)在 SDWebImageCache 中尋找圖片是否有對(duì)應(yīng)的緩存, 它會(huì)以u(píng)rl 作為數(shù)據(jù)的索引先在內(nèi)存中尋找是否有對(duì)應(yīng)的緩存
2.如果緩存未找到就會(huì)利用通過(guò)MD5處理過(guò)的key來(lái)繼續(xù)在磁盤(pán)中查詢(xún)對(duì)應(yīng)的數(shù)據(jù), 如果找到了, 就會(huì)把磁盤(pán)中的數(shù)據(jù)加載到內(nèi)存中,并將圖片顯示出來(lái)
3.如果在內(nèi)存和磁盤(pán)緩存中都沒(méi)有找到,就會(huì)向遠(yuǎn)程服務(wù)器發(fā)送請(qǐng)求,開(kāi)始下載圖片
4.下載后的圖片會(huì)加入緩存中,并寫(xiě)入磁盤(pán)中
5.整個(gè)獲取圖片的過(guò)程都是在子線程中執(zhí)行,獲取到圖片后回到主線程將圖片顯示出來(lái)

SDWebImage原理:
調(diào)用類(lèi)別的方法:

  1. 從內(nèi)存(字典)中找圖片(當(dāng)這個(gè)圖片在本次使用程序的過(guò)程中已經(jīng)被加載過(guò)),找到直接使用。
  2. 從沙盒中找(當(dāng)這個(gè)圖片在之前使用程序的過(guò)程中被加載過(guò)),找到使用,緩存到內(nèi)存中。
  3. 從網(wǎng)絡(luò)上獲取,使用,緩存到內(nèi)存,緩存到沙盒。

待續(xù)。。。。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 移動(dòng)APP安全事件泄漏的信息主要是以用戶(hù)的姓名、地址、賬號(hào)、密碼、手機(jī)號(hào)等信息為主,特別是尤其金融理財(cái)類(lèi)APP。鼎...
    必安全AppBeSafe閱讀 375評(píng)論 0 2
  • 相信大家都會(huì)用各種各樣的搜索工具進(jìn)行搜索,但是你真的會(huì)搜索么? 在進(jìn)行搜索的時(shí)候,如果不能進(jìn)行有效的篩選,我們很難...
    初心_a2da閱讀 395評(píng)論 0 1
  • 100天行動(dòng)清單 11月-12月5日為純休息期 001書(shū)籍閱讀 2本專(zhuān)業(yè)書(shū)《室內(nèi)空間布局與尺度設(shè)計(jì)》、《字型之不思...
    粉色馬甲閱讀 359評(píng)論 0 1
  • 沒(méi)有熱水了,不用洗澡了,也不想洗澡了。 明天早上英語(yǔ)口語(yǔ)考試,要朗讀課文,沒(méi)啥準(zhǔn)備。 他們都有一顆認(rèn)真做事的心,而...
    愛(ài)元若哥哥閱讀 137評(píng)論 0 4

友情鏈接更多精彩內(nèi)容