2019-02-15

1.http請求方式?

1.HTTP的請求方式有3種,分別是:POST、GET、HEAD。POST和GET方法是用于數(shù)據(jù)發(fā)送的。
2.POST:它將要發(fā)送的數(shù)據(jù)單獨放在一個流中進(jìn)行發(fā)送,
而不是附加在URL地址后面,好處是這些數(shù)據(jù)不會出現(xiàn)在URL地址中。
3.GET:它將要發(fā)送的數(shù)據(jù)直接添加在URL后面,
這樣的好處是可以直接將數(shù)據(jù)加在URL后,而不需在用另外的流來發(fā)送這些數(shù)據(jù),
但是缺點也顯而易見,它將用戶的信息顯示出來了。
4.HEAD:它是請求資源的元數(shù)據(jù)方法。在具體的應(yīng)用中,我暫時還沒遇到過,

2.socket編程簡述

1.socket是基于TCP/IP的協(xié)議,Socket可以支持?jǐn)?shù)據(jù)的發(fā)送和接收,
它會定義一種稱為套接字的變量,發(fā)送數(shù)據(jù)時首先創(chuàng)建套接字,
然后使用該套接字的sendto等方法對準(zhǔn)某個IP/端口進(jìn)行數(shù)據(jù)發(fā)送;
接收端也首先創(chuàng)建套接字,然后將該套接字綁定到一個IP/端口上,
所有發(fā)向此端口的數(shù)據(jù)會被該套接字的recv等函數(shù)讀出。如同讀出文件中的數(shù)據(jù)一樣。
2.TCP/IP的socket提供下列三種類型套接字。 流式套接字、數(shù)據(jù)報式套接字、原始式套接字。
3.客戶端編程步驟:
3.1.加載套接字庫,創(chuàng)建套接字(WSAStartup()/socket());
3.2.向服務(wù)器發(fā)出連接請求(connect());
3.3.和服務(wù)器端進(jìn)行通信(send()/recv());
3.4.關(guān)閉套接字,關(guān)閉加載的套接字庫(closeSocket()/WSACleanup())。

3.App需要加載超大量的數(shù)據(jù),給服務(wù)器發(fā)送請求,但是服務(wù)器卡住了如何解決?

1.設(shè)置超時時間
2.給用戶提示請求超時
3.根據(jù)用戶操作再次請求數(shù)據(jù)

4.HTTP的通信的 發(fā)送請求、接收響應(yīng) 包含哪些內(nèi)容?OC中是怎樣實現(xiàn)的?

1.一個請求包含如下內(nèi)容:
1.1.請求頭:包含了對客戶端的環(huán)境描述、客戶端請求的主機(jī)地址等信息
1.2.包含了請求方法、請求資源路徑、HTTP協(xié)議版本
1.3.客戶端發(fā)給服務(wù)器的具體數(shù)據(jù),比如文件數(shù)據(jù)
2.一個響應(yīng)包括:
2.1.狀態(tài)行:包含了HTTP協(xié)議版本、狀態(tài)碼、狀態(tài)英文名稱 HTTP/1.1 200 OK
2.2.響應(yīng)頭:包含了對服務(wù)器的描述、對返回數(shù)據(jù)的描述
2.3.實體內(nèi)容:服務(wù)器返回給客戶端的具體數(shù)據(jù),比如文件數(shù)據(jù)

5.什么是三次握手與四次揮手?

1.三次握手實現(xiàn)的過程:
第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);
第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),
同時自己也發(fā)送一個SYN包(syn=k),即SYN+ACK包,此時服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包
ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。

2.四次揮手:

第一次: 客戶端向服務(wù)器發(fā)送一個帶有結(jié)束標(biāo)記的報文。
第二次:服務(wù)器收到報文后,向客戶端發(fā)送一個確認(rèn)序號,同時通知自己相應(yīng)的應(yīng)用程序:對方要求關(guān)閉連接
第三次: 服務(wù)器向客戶端發(fā)送一個帶有結(jié)束標(biāo)記的報文。
第四次: 客戶端收到報文后,向服務(wù)器發(fā)送一個確認(rèn)序號。鏈接關(guān)閉。

6.分析json、xml的區(qū)別?json、xml解析方式的底層是如何處理的?

1. json與xml的區(qū)別:
可讀性方面:基本相同,xml的可讀性比較好
可擴(kuò)展性方面:都具有很好的擴(kuò)展性
編碼難度方面:相對而言:JSON的編碼比較容易
解碼難度:json的解碼難度基本為零,xml需要考慮子節(jié)點和父節(jié)點
數(shù)據(jù)體積方面:json相對于xml來講,數(shù)據(jù)體積小,傳遞的速度跟快些
數(shù)據(jù)交互方面:json與JavaScript的交互更加方面,更容易解析處理,更好的數(shù)據(jù)交互
數(shù)據(jù)描述方面:xml對數(shù)據(jù)描述性比較好
傳輸速度方面:json的速度遠(yuǎn)遠(yuǎn)快于xml

2.JSON底層原理:
遍歷字符串中的字符,最終根據(jù)格式規(guī)定的特殊字符,比如{}號,[]號, : 號 等進(jìn)行區(qū)分,
{}號是一個字典 的開始,[]號是一個數(shù)組的開始, : 號是字典的鍵和值的分水嶺,
最終乃是將json數(shù)據(jù)轉(zhuǎn)化為字典,字典中值可能是字典,數(shù)組,或字符串而已。

3.XML底層原理:
XML解析常用的解析方法有兩種:DOM解析和SAX解析。
DOM 采用建立樹形結(jié)構(gòu)的方式訪問 XML 文檔,而 SAX 采用的事件模型。
DOM 解析把 XML 文檔轉(zhuǎn)化為一個包含其內(nèi)容的樹,并可以對樹進(jìn)行遍歷。
使用 DOM 解析器的時候需 要處理整個 XML 文檔,所以對性能和內(nèi)存的要求比較高。
SAX在解析 XML 文檔的時候可以觸發(fā)一系列的事件,當(dāng)發(fā)現(xiàn)給定的tag的時候,
它可以激活一個回調(diào)方法,告訴該方法制定的標(biāo)簽已經(jīng)找到。
SAX 對內(nèi)存的要求通常會比較低,因為它讓開發(fā)人員自己來決定所要處理的tag。
特別是當(dāng)開發(fā)人員只需要處理文檔中所包含的部分?jǐn)?shù)據(jù)時,SAX 這種擴(kuò)展能力得到了更好的體現(xiàn)。

4.HTTP協(xié)議的組成和特性?

1.http 請求由三部分組成,分別是:請求行、消息報頭、請求正文.
2.HTTP協(xié)議的主要特點可概括如下:
2.1.支持客戶/服務(wù)器模式。
2.2.簡單快速:客戶向服務(wù)器請求服務(wù)時,只需傳送請求方法和路徑。方法有 GET、HEAD、POST。
每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同。由于 HTTP 協(xié)議簡單,
使得 HTTP 服務(wù)器的程序規(guī)模小,因而通信速度很快。
2.3.靈活:HTTP 允許傳輸任意類型的數(shù)據(jù)對象。正在傳輸?shù)念愋陀?Content-Type 加以標(biāo)記
2.4.無連接:無連接的含義是限制每次連接只處理一個請求。服務(wù)器處理完客戶的請求,
并收到客戶的應(yīng)答后,即斷開連接。采用這種方式可以節(jié)省傳輸時間
2.5..無狀態(tài):HTTP 協(xié)議是無狀態(tài)協(xié)議。無狀態(tài)是指協(xié)議對于事務(wù)處理沒有記憶能力。
缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳,
這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大。另一方面,
在服務(wù)器不需要先前信息時它的應(yīng)答就較快。
  1. TCP/UDP 區(qū)別?
TCP: 是傳輸控制協(xié)議:是面連接的,那么運行環(huán)境必然要求其可靠性不可丟包有
良好的擁塞控制機(jī)制如http ftp telnet 等
UDP: 是用戶數(shù)據(jù)報協(xié)議: 主要用在實時性要求高以及對質(zhì)量相對較弱的地方,
但面對現(xiàn)在高質(zhì)量的線路不是容易丟包除非是一些擁塞條件下, 如流媒體

6.http和scoket通信的區(qū)別?socket連接相關(guān)庫,TCP,UDP的連接方法,HTTP的幾種常用方式?

1.http和scoket通信的區(qū)別:
http是客戶端用http協(xié)議進(jìn)行請求,發(fā)送請求時候需要封裝http請求頭,并綁定請求
的數(shù)據(jù),服務(wù)器一般有web服務(wù)器配合(當(dāng)然也非絕對)。 http請求方式為客戶端
主動發(fā)起請求,服務(wù)器才能給響應(yīng),一次請求完畢后則斷開連接,以節(jié)省資源。服
務(wù)器不能主動給客戶端響應(yīng)(除非采取http長連接技術(shù))。

scoket是客戶端跟服務(wù)器直接使用socket“套接字”進(jìn)行連接,并沒有規(guī)定連接后
斷開,所以客戶端和服務(wù)器可以保持連接通道,雙方都可以主動發(fā)送數(shù)據(jù)。一般在
游戲開發(fā)或股票開發(fā)這種要求即時性很強(qiáng)并且保持發(fā)送數(shù)據(jù)量比較大的場合使
用。主要使用類是CFSocketRef。

7.卡頓優(yōu)化

1.在CPU層次:
1.1.盡量用輕量級的對象,比如用不到事件處理的地方,可以考慮使用CALayer取代UIView
1.2.盡量提前計算好布局,在有需要時一次性調(diào)整對應(yīng)的屬性,不要多次修改屬性
1.3.Autolayout會比直接設(shè)置frame消耗更多的CPU資源
1.4.圖片的size最好剛好跟UIImageView的size保持一致
1.5.控制一下線程的最大并發(fā)數(shù)量
1.6.盡量把耗時的操作放到子線程:文本處理(尺寸計算、繪制),圖片處理(解碼、繪制)

2.GPU層次:
2.1.盡量避免短時間內(nèi)大量圖片的顯示,盡可能將多張圖片合成一張進(jìn)行顯示
2.2.GPU能處理的最大紋理尺寸是4096x4096,一旦超過這個尺寸,就會占用
CPU資源進(jìn)行處理,所以紋理盡量不要超過這個尺寸
2.3.盡量減少視圖數(shù)量和層次
2.4.減少透明的視圖(alpha<1),不透明的就設(shè)置opaque為YES
2.5.盡量避免出現(xiàn)離屏渲染

關(guān)于離屏渲染:
GPU有2種渲染方式,當(dāng)前屏幕渲染:在當(dāng)前用于顯示的屏幕緩沖區(qū)進(jìn)行渲染操作,
離屏渲染:在當(dāng)前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進(jìn)行渲染操作

離屏渲染消耗性能的原因:需要創(chuàng)建新的緩沖區(qū),離屏渲染的整個過程,需要
多次切換上下文環(huán)境,先是從當(dāng)前屏幕(On-Screen)切換到離屏(Off-
Screen);等到離屏渲染結(jié)束以后,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上,
又需要將上下文環(huán)境從離屏切換到當(dāng)前屏幕

哪些操作會觸發(fā)離屏渲染?
1.光柵化: layer.shouldRasterize = YES
2.遮罩: layer.mask
3.圓角:同時設(shè)置layer.masksToBounds = YES、layer.cornerRadius大于0
4.陰影,layer.shadowXXX ,如果設(shè)置了layer.shadowPath就不會產(chǎn)生離屏渲染
  1. APP的啟動流程
APP啟動分為兩種:
冷啟動:從零開始啟動app
熱啟動:APP已經(jīng)在內(nèi)存中,在后臺存活著,再次點擊圖標(biāo)啟動APP
app啟動時間的優(yōu)化主要針對 冷啟動進(jìn)行優(yōu)化

app冷啟動 可以概括為3大類,dyld,runtime,main
1.dyld:app的動態(tài)鏈接器,可以裝載Mach-o文件(可執(zhí)行文件,動態(tài)庫)
1.2.啟動app時,dyld所做的事情有:
1.2.1.裝載app的可執(zhí)行文件,同時遞歸加載所有依賴的動態(tài)庫。
1.2.2.當(dāng)dyld把可執(zhí)行文件和動態(tài)庫加載完畢,會通知runtime進(jìn)行下一步處理。

2.app啟動-runtime所做的事:
2.1.調(diào)用map_images進(jìn)行可執(zhí)行文件內(nèi)容的解析和處理。
2.2.在load_images中調(diào)用 call_load_methods,調(diào)用Class和Category的+load方法。
2.3.進(jìn)行各種objc結(jié)構(gòu)的初始化。(注冊objc類,初始化類對象)
2.4.調(diào)用C++靜態(tài)初始化器和attribute((constructor))修飾的函數(shù)
2.5.到此為止,可執(zhí)行文件和動態(tài)庫中所有的符號(Class,Protocol,
Selector,IMP,…)都已經(jīng)按格式成功加載到內(nèi)存中,被runtime 所管理

3.app啟動-main()的事情
3.1.APP的啟動由dyld主導(dǎo),將可執(zhí)行文件加載到內(nèi)存,順便加載所有依賴的動態(tài)庫
3.2.runtime負(fù)責(zé)加載成objc定義的結(jié)構(gòu)
3.3.所有初始化工作結(jié)束后,dyld就會調(diào)用main函數(shù)
3.4.UIApplicationMain函數(shù),AppDelegate的
application:didFinishLaunchingWithOptions:方法

9.APP的啟動優(yōu)化

1.dyld階段:
1.1.減少動態(tài)庫、合并一些動態(tài)庫(定期清理不必要的動態(tài)庫)
1.2.減少Objc類、分類的數(shù)量、減少Selector數(shù)量(定期清理不必要的類、分類)
1.3.減少C++虛函數(shù)數(shù)量

2.runtime階段:
2.1.用+initialize方法和dispatch_once取代所有的attribute((constructor))、
C++靜態(tài)構(gòu)造器、ObjC的+load

3.main()階段
3.1.在不影響用戶體驗的前提下,盡可能將一些操作延遲,不要全部都放在
finishLaunching方法中。
3.2.資源的按需加載。

10.安裝包瘦身

1.安裝包主要由 可執(zhí)行文件和資源組成
2.資源主要包含,圖片,音頻,視頻,采取無損壓縮的方式壓縮資源。去除無效的資源。
3.可執(zhí)行文件瘦身:
3.1.編譯器優(yōu)化:Strip Linked Product、Make Strings Read-Only、
Symbols Hidden by Default等參數(shù)設(shè)置為YES
3.2.去掉異常支持,Enable C++ Exceptions、Enable Objective-C Exceptions
設(shè)置為NO, Other C Flags添加-fno-exceptions
3.3.檢測出重復(fù)代碼、未被調(diào)用的代碼

11.iOS提升性能

1. 在正確的地方使用reuseIdentifier
為了性能最優(yōu)化,UICollectionViewCell和UITableViewCell應(yīng)該使用標(biāo)識符進(jìn)行復(fù)用,
也應(yīng)該在header和footer views中使用reuseIdentifiers。

2. 盡可能使Views透明
如果你有透明的Views你應(yīng)該設(shè)置它們的opaque(不透明)屬性為YES。(opaque)
這個屬性給渲染系統(tǒng)提供了一個如何處理這個view的提示。如果設(shè)為YES, 渲
染系統(tǒng)就認(rèn)為這個view是完全不透明的,這使得渲染系統(tǒng)優(yōu)化一些渲染過程和
提高性能。如果設(shè)置為NO,渲染系統(tǒng)正常地和其它內(nèi)容組成這個View。默認(rèn)值
是YES。,如果一個圖層是完全不透明的,則系統(tǒng)直接顯示該圖層的顏色即可。而
如果圖層是帶透明效果的,則會引入更多的計算,因為需要把下面的圖層也包括進(jìn)
來,進(jìn)行混合后顏色的計算。

3.避免過于龐大的XIB
加載一個XIB的時候所有內(nèi)容都被放在了內(nèi)存里,包括任何圖片。如果有一個不
會即刻用到的view,你這就是在浪費寶貴的內(nèi)存資源了。

4. 不要阻塞主線程
UIKit在主線程上做所有工作,渲染,管理觸摸反應(yīng),回應(yīng)輸入等都需要在它上
面完成。如果你的代碼真的阻塞了主線程,app會失去反應(yīng),大部分阻礙主進(jìn)程
的情形是app在做一些牽涉到讀寫外部資源的I/O操作,比如存儲或者網(wǎng)絡(luò)?;?者使用像 AFNetworking這樣的框架來異步地做這些操作。
如果你需要做其它類型的需要耗費巨大資源的操作(比如時間敏感的計算或者存
儲讀寫)那就用 Grand Central Dispatch,或者 NSOperation 和 
NSOperationQueues.

5. 在Image Views中調(diào)整圖片大小
如果要在UIImageView中顯示一個來自bundle的圖片,你應(yīng)保證圖片的大小和
UIImageView的大小相同。在運行中縮放圖片是很耗費資源的,特別是
UIImageView嵌套在UIScrollView中的情況下。
如果圖片是從遠(yuǎn)端服務(wù)加載的你不能控制圖片大小,比如在下載前調(diào)整到合適
大小的話,你可以在下載完成后,最好是用background thread,縮放一次,然
后在UIImageView中使用縮放后的圖片。

6. 選擇正確的Collection
Arrays: 有序的一組值。使用index來lookup很快,使用value lookup很慢, 插入/刪除很慢。
Dictionaries: 存儲鍵值對。 用鍵來查找比較快。
Sets: 無序的一組值。用值來查找很快,插入/刪除很快。

7. 打開gzip壓縮
大量app依賴于遠(yuǎn)端資源和第三方API,你可能會開發(fā)一個需要從遠(yuǎn)端下載XML, 
JSON, HTML或者其它格式的app。減小文檔的一個方式就是在服務(wù)端和你的
app中打開gzip。這對于文字這種能有更高壓縮率的數(shù)據(jù)來說會有更顯著的效
用。好消息是,iOS已經(jīng)在NSURLConnection中默認(rèn)支持了gzip壓縮,當(dāng)然
AFNetworking這些基于它的框架亦然。

8. 重用和延遲加載Views

9. Cache, Cache, 還是Cache!
緩存所需要的,也就是那些不大可能改變但是需要經(jīng)常讀取的東西。
比如遠(yuǎn)端服務(wù)器的響應(yīng),圖片,甚至計算結(jié)果,比如UITableView的行高。
NSCache和NSDictionary類似,不同的是系統(tǒng)回收內(nèi)存的時候它會自動刪掉它的內(nèi)容。

10. 權(quán)衡渲染方法
11. 處理內(nèi)存警告

12. 重用大開銷的對象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又
不可避免地需要使用它們,比如從JSON或者XML中解析數(shù)據(jù)。
想要避免使用這個對象的瓶頸你就需要重用他們,可以通過添加屬性到你的
class里或者創(chuàng)建靜態(tài)變量來實現(xiàn)。

13. 避免反復(fù)處理數(shù)據(jù)
許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)。在服
務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要。在內(nèi)存中操作數(shù)據(jù)使它們滿足你
的數(shù)據(jù)結(jié)構(gòu)是開銷很大的。比如你需要數(shù)據(jù)來展示一個table view,最好直接從服
務(wù)器取array結(jié)構(gòu)的數(shù)據(jù)以避免額外的中間數(shù)據(jù)結(jié)構(gòu)改變。類似的,如果需要從
特定key中取數(shù)據(jù),那么就使用鍵值對的dictionary。

14. 選擇正確的數(shù)據(jù)格式(JSON還是XML)
15. 正確地設(shè)定Background Images
在View里放背景圖片使用UIColor的 colorWithPatternImage來設(shè)置背景色;
如果你使用全畫幅的背景圖,你就必須使用UIImageView因為UIColor的
colorWithPatternImage是用來創(chuàng)建小的重復(fù)的圖片作為背景的。這種情形下使
用UIImageView可以節(jié)約不少的內(nèi)存:
如果你用小圖平鋪來創(chuàng)建背景,你就需要用UIColor的colorWithPatternImage來
做了,它會更快地渲染也不會花費很多內(nèi)存:

16. 減少使用Web特性
UIWebView很有用,用它來展示網(wǎng)頁內(nèi)容或者創(chuàng)建UIKit很難做到的動畫效果是
很簡單的一件事。UIWebView并不像驅(qū)動Safari的那么快,想要更高的性能你
就要調(diào)整下你的HTML了。第一件要做的事就是盡可能移除不必要的
javascript,避免使用過大的框架。能只用原生js就更好了。另外,盡可能異步
加載例如用戶行為統(tǒng)計script這種不影響頁面表達(dá)的javascript。

17. 設(shè)定Shadow Path
使用shadow path的話iOS就不必每次都計算如何渲染,它使用一個預(yù)先計算好
的路徑。但問題是自己計算path的話可能在某些View中比較困難,且每當(dāng)view
的frame變化的時候你都需要去update shadow path.

18. 優(yōu)化你的Table View
為了保證table view平滑滾動,確保你采取了以下的措施:
正確使用reuseIdentifier來重用cells
盡量使所有的view 不透明(opaque),包括cell自身
避免漸變,圖片縮放,
緩存行高
如果cell內(nèi)現(xiàn)實的內(nèi)容來自web,使用異步加載,緩存請求結(jié)果
使用shadowPath來畫陰影
減少subviews的數(shù)量
盡量不使用cellForRowAtIndexPath:,如果你需要用到它,只用一次然后緩存結(jié)果
使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù)
盡量使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight來設(shè)定固定
的高,不要請求delegate。

19. 選擇正確的數(shù)據(jù)存儲選項
NSUserDefaults它只適用于小數(shù)據(jù),比如一些簡單的布爾型的設(shè)置選項。
XML這種結(jié)構(gòu)化檔案需要讀取整個文件到內(nèi)存里去解析,這樣是很不高效的。
使用SAX又是一個很麻煩的事情。
NSCoding也需要讀寫文件,所以效率也不是很好。
當(dāng)存儲大塊數(shù)據(jù)時,以上的方法都不適用. 在這種應(yīng)用場景下,使用SQLite 或者 Core Data比較好。

20. 加速啟動時間
盡可能做更多的異步任務(wù),比如加載遠(yuǎn)端或者數(shù)據(jù)庫數(shù)據(jù),解析數(shù)據(jù)。
避免過于龐大的XIB,因為他們是在主線程上加載的。
減少或者合并動態(tài)庫。

21. 使用Autorelease Pool
NSAutoreleasePool負(fù)責(zé)釋放block中的autoreleased objects。一般情況下它會
自動被UIKit調(diào)用。但是有些狀況下你也需要手動去創(chuàng)建它。
假如你創(chuàng)建很多臨時對象,你會發(fā)現(xiàn)內(nèi)存一直在減少直到這些對象被release的
時候。這是因為只有當(dāng)UIKit用光了autorelease pool的時候memory才會被釋
放。
好消息是你可以在你自己的@autoreleasepool里創(chuàng)建臨時的對象來避免這個行
為:
    NSArray *urls = <# An array of file URLs #>;
    for(NSURL *url in urls) {
        @autoreleasepool {
            NSError *error;
            NSString *fileContents = [NSString stringWithContentsOfURL:url
                              encoding:NSUTF8StringEncoding error:&error];

       }
    }

22. 選擇是否緩存圖片
常見的從bundle中加載圖片的方式有兩種,一個是用imageNamed,二是用
imageWithContentsOfFile,第一種比較常見一點。imageNamed的優(yōu)點是當(dāng)加
載時會緩存圖片。imageWithContentsOfFile僅加載圖片。如果你要加載一個大
圖片而且是一次性使用,那么就沒必要緩存這個圖片,用
imageWithContentsOfFile足矣,這樣不會浪費內(nèi)存來緩存它。
然而,在圖片反復(fù)重用的情況下imageNamed是一個好得多的選擇。

23. 盡量避免日期格式轉(zhuǎn)換

12.KVO、KVC 是什么,各自底層的實現(xiàn)原理?

KVC底層原理:
 當(dāng)一個對象調(diào)用setValue:forKey: 方法時,方法內(nèi)部會做以下操作:
 1.判斷有沒有指定key的set方法,如果有set方法,就會調(diào)用set方法,給該屬性賦值
 2.如果沒有set方法,判斷有沒有跟key值相同且?guī)в邢聞澗€的成員屬性(_key).如果有,直接給該成員屬性進(jìn)行賦值
 3.如果沒有成員屬性_key,判斷有沒有跟key相同名稱的屬性.如果有,直接給該屬性進(jìn)行賦值
 4.如果都沒有,就會調(diào)用 valueforUndefinedKey 和setValue:forUndefinedKey:方法
KVO 的底層實現(xiàn)原理:
1.KVO 是基于 runtime 機(jī)制實現(xiàn)的
2.當(dāng)一個對象(假設(shè)是person對象,對應(yīng)的類為 JLperson)的屬性值age發(fā)
生改變時,系統(tǒng)會自動生成一個繼承自JLperson的類NSKVONotifying_JLPerson,
在這個類的 setAge 方法里面調(diào)用
    [super setAge:age];
    [self willChangeValueForKey:@"age"];
    [self didChangeValueForKey:@"age"];
 三個方法,而后面兩個方法內(nèi)部會主動調(diào)用
 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
方法,在該方法中可以拿到屬性改變前后的值.

13.消息轉(zhuǎn)發(fā)機(jī)制原理?

消息發(fā)送和轉(zhuǎn)發(fā)流程可以概括為:消息發(fā)送(Messaging)是 Runtime 
通過 selector 快速查找 IMP 的過程,有了函數(shù)指針就可以執(zhí)行對應(yīng)的
方法實現(xiàn);消息轉(zhuǎn)發(fā)(Message Forwarding)是在查找 IMP 失敗后執(zhí)
行一系列轉(zhuǎn)發(fā)流程的慢速通道,如果不作轉(zhuǎn)發(fā)處理,則會打日志和拋出異常。

14.說說你理解的weak屬性,什么情況下使用 weak 關(guān)鍵字,相比 assign 有什么不同??

1.weak只能用于修飾對象類型,基本數(shù)據(jù)類型不能使用
2.assign修飾對象和基本數(shù)據(jù)類型都可以,但是只是簡單地進(jìn)行賦值操作而已
注意:assign修飾的對象,在釋放之后,指針的地址還是存在的,也就
是說指針并沒有被置為nil,造成野指針。對象一般分配在堆上的某塊內(nèi)
存,如果在后續(xù)的內(nèi)存分配中,剛好分到了這塊地址,程序就會崩潰。
weak修飾的對象在釋放之后,指針地址會被置為nil。所以現(xiàn)在一般弱
引用就是用weak。

15.項目中網(wǎng)絡(luò)層如何做安全處理?

1.判斷API的調(diào)用請求是否來自于經(jīng)過授權(quán)的APP。如若不是則拒絕請求訪問
2.在數(shù)據(jù)請求的過程中進(jìn)行URL加密處理:防止反編譯,接口信息被靜態(tài)分析。
3.數(shù)據(jù)傳輸加密:對客戶端傳輸數(shù)據(jù)提供有效的加密方案,以防止網(wǎng)絡(luò)接口的攔截。
4.盡量使用HTTPS,可以有效的避免接口數(shù)據(jù)在傳輸中被攻擊。

16.main()之前的過程有哪些?

1.dyld 開始將程序二進(jìn)制文件初始化
2.交由Image_loader 讀取 image,其中包含了我們的類,方法等各種符號
(Class、Protocol 、Selector、 IMP)
3.由于runtime 向dyld 綁定了回調(diào),當(dāng)image加載到內(nèi)存后,dyld會通知runtime進(jìn)行處理
4.runtime 接手后調(diào)用map_images做解析和處理
5.接下來load_images 中調(diào)用call_load_methods方法,遍歷所有加載
進(jìn)來的Class,按繼承層次依次調(diào)用Class的+load和其他Category的+load方法
6.至此 所有的信息都被加載到內(nèi)存中
7.最后dyld調(diào)用真正的main函數(shù)

17.怎么高效的實現(xiàn)控件的圓角效果?

通常label.layer.cornerRadius=x就可以設(shè)置圓角,但是cornerRadius只會影響
視圖的背景顏色和border,對于內(nèi)部還有子視圖的控件就會設(shè)置不成功(如
UILabel),對于內(nèi)部還有子視圖的控件還需要設(shè)置
label.layer.masksToBounds=true才能使cornerRadius屬性生效,此時會造成離屏渲染。
使用貝塞爾曲線繪制圓角。

18.NSIRLConnection 和NSLRLSession 的區(qū)別是 么? NSURLProtocol是做什么的?

1.下載
NSURLConnection下載文件時,先是將整個文件下載到內(nèi)存,然后再寫入到沙
盒,如果文件比較大,就會出現(xiàn)內(nèi)存暴漲的情況。
而使用NSURLSessionUploadTask下載文件,會默認(rèn)下載到沙盒中的tem文件
中,不會出現(xiàn)內(nèi)存暴漲的情況,但是在下載完成后會把tem中的臨時文件刪除,
需要在初始化任務(wù)方法時,在completionHandler回調(diào)中增加保存文件的代碼。
2.請求方法的控制
NSURLConnection實例化對象,實例化開始,默認(rèn)請求就發(fā)送(同步發(fā)送),不需
要調(diào)用start方法。而cancel可以停止請求的發(fā)送,停止后不能繼續(xù)訪問,需要
創(chuàng)建新的請求。
NSURLSession有三個控制方法,取消(cancel)、暫停(suspend)、繼續(xù)
(resume),暫停以后可以通過繼續(xù)恢復(fù)當(dāng)前的請求任務(wù)。
使用NSURLSession進(jìn)行斷點下載更加便捷.
NSURLSession的構(gòu)造方法中有一個NSURLSessionConfiguration類的參數(shù)可
以設(shè)置配置信息,其決定了cookie,安全和高速緩存策略,最大主機(jī)連接數(shù),
資源管理,網(wǎng)絡(luò)超時等配置。NSURLConnection不能進(jìn)行這個配置,相比較與
NSURLConnection依賴與一個全局的配置對象,缺乏靈活性而言,
NSURLSession有很大的改進(jìn)

3.NSURLProtocol:使用它可以輕松地重定義整個URL Loading System。當(dāng)你
注冊自定義NSURLProtocol后,就有機(jī)會對所有的請求進(jìn)行統(tǒng)一的處理
3.1.自定義請求和響應(yīng)
3.2.提供自定義的全局緩存支持
3.3.重定向網(wǎng)絡(luò)請求
3.4.提供HTTP Mocking (方便前期測試)
3.5.其他一些全局的網(wǎng)絡(luò)請求修改需求

19.AutoLayout 中的優(yōu)先級是什么? UIScrollView 中使用Autolayout 會出現(xiàn)什么問題?

 代碼計算frame -> autoreszing(父控件和子控件的關(guān)系) -> autolayout(任何控件
都可以產(chǎn)生關(guān)系) -> sizeclass

注意點:
1.子控件的尺寸不能通過關(guān)聯(lián)UIScrollView的來計算(UIScrollView的子控件和
其關(guān)聯(lián)的約束是用來計算UIScrollView的contentsize的),可以考慮通過以下方式計算:
1.1.可以設(shè)置固定值,width=100,height=200
1.2.可以相對于UIScrollView以外的其他控件關(guān)聯(lián)約束來計算。

2.UIScrollView的frame應(yīng)該通過子控件以外的其他控件來計算。
3.UIScrollView的contentsize通過子控件來計算,原則是:根據(jù)子控件的尺寸以
及子控件與UIScrollView之間的間距。

20.如何處理UITableVier 中Cell 動態(tài)計算高度的問題,都有哪些方案?

1、你的Cell要使用AutoLayout來布局約束這是必須的;
設(shè)置tableview的estimatedRowHeight為一個非零值,這個屬性是設(shè)置一個預(yù)估
的高度值,不用太精確。
設(shè)置tableview的rowHeight屬性為UITableViewAutomaticDimension
2.第三方 UITableView+FDTemplateLayoutCell

21.UIView和CALayer是什么關(guān)系?

創(chuàng)建UIView對象時,UIView內(nèi)部會自動創(chuàng)建一個層(CALayer對象),通過
UIView的layer屬性可以訪問這個層。當(dāng)UIView需要顯示到屏幕上時,會調(diào)用
drawRect:方法進(jìn)行繪圖渲染,并且會將所有內(nèi)容繪制在自己的層上,繪圖完畢
后,系統(tǒng)會將層拷貝到屏幕上,于是就完成了UIView的顯示

UIView相比CALayer最大區(qū)別是UIView繼承自UIResponder,可以響應(yīng)用戶事
件,而CALayer不可以;UIView側(cè)重于對顯示內(nèi)容的管理,CALayer側(cè)重于對
內(nèi)容的繪制。

UIView本身,更像是一個CALayer的管理器,訪問它的和繪圖、坐標(biāo)相關(guān)的屬
性,如frame,bounds等,實際上內(nèi)部都是訪問它所在CALayer的相關(guān)屬性
UIView和CALayer是相互依賴的關(guān)系。UIView依賴CALayer提供的內(nèi)容,
CALayer依賴UIView提供的容器來顯示繪制的內(nèi)容。歸根到底CALayer是這一
切的基礎(chǔ),如果沒有CALayer,UIView自身也不會存在,UIView是一個特殊的
CALayer實現(xiàn),添加了響應(yīng)事件的能力。

使用例子:向UIView的layer上添加子layer,來使目標(biāo)View上敷上一層黑色的透明薄膜。 

22.你在什么場景下會選擇使 Category ?類別有什么作用?

1.分類就是對一個類的功能進(jìn)行擴(kuò)展,Category提供了一種比繼承更為簡潔的方
法來對類進(jìn)行擴(kuò)展,無需創(chuàng)建對象類的子類就能為現(xiàn)有的類添加新的方法,可
以為任何已經(jīng)存在的類添加方法,包括系統(tǒng)框架UIKit等。
2.可以把類的實現(xiàn)分開在不同的文件里面,這樣做的好處:可以將類的實現(xiàn)分
散到多個不同的文件或者不同的框架中,方便代碼的管理。也可以對框架提供類的擴(kuò)展。
3.創(chuàng)建對私有方法的前向引用:如果其他類中的方法未實現(xiàn),在你訪問其他類
的私有方法時編譯器報錯這時使用類別,在類別中聲明這些方法(不必提供方
法實現(xiàn)),編譯器就不會再產(chǎn)生警告

4.category局限性
category只能給某個已有的類擴(kuò)充方法,不能擴(kuò)充成員變量。
category中也可以添加屬性,只不過@property只會生成setter和getter的聲明,
生成setter和getter的實現(xiàn)以及成員變量。
如果category中的方法和類中原有方法同名,運行時會優(yōu)先調(diào)用category中的方法

23.講講iOS事件響應(yīng)鏈的原理?

1.大多數(shù)事件的分發(fā)都是依賴響應(yīng)鏈的。響應(yīng)鏈?zhǔn)怯梢幌盗墟溄釉谝黄鸬捻憫?yīng)
者(UIResponse子類)組成的。一般情況下,一條響應(yīng)鏈開始于第一響應(yīng)者,結(jié)
束于application對象。如果一個響應(yīng)者不能處理事件,則會將事件沿著響應(yīng)鏈傳到下一響應(yīng)者。
2.一般情況下,一條響應(yīng)鏈開始于第一響應(yīng)者,結(jié)束于application對象。因此我
們只要確定第一響應(yīng)者,就可以確定整條響應(yīng)鏈了。

3.當(dāng)用戶觸發(fā)某一事件(觸摸事件或運動事件)后,UIKit會創(chuàng)建一個事件對象
(UIEvent),該對象包含一些處理事件所需要的信息。然后事件對象被放到一個
事件隊列中。這些事件按照先進(jìn)先出的順序來處理。當(dāng)處理事件時,程序的
UIApplication對象會從隊列頭部取出一個事件對象,將其分發(fā)出去。通常首先
是將事件分發(fā)給程序的主window對象,對于觸摸事件來講,window對象會首先
嘗試將事件分發(fā)給觸摸事件發(fā)生的那個視圖上。這一視圖通常被稱為hit-test視
圖,而查找這一視圖的過程就叫做hit-testing。

系統(tǒng)使用hit-testing來找到觸摸下的視圖,它檢測一個觸摸事件是否發(fā)生在相應(yīng)
視圖對象的邊界之內(nèi)(即視圖的frame屬性,這也是為什么子視圖如果在父視圖
的frame之外時,是無法響應(yīng)事件的)。如果在,則會遞歸檢測其所有的子視
圖。包含觸摸點的視圖層次架構(gòu)中最底層的視圖就是hit-test視圖。在檢測出hit-
test視圖后,系統(tǒng)就將事件發(fā)送給這個視圖來進(jìn)行處理

事件傳遞鏈:

initial view若不能處理事件,則傳到其父視圖view,
view若不能處理,則傳到其父視圖,因為它還不是最上層視圖,
這里view的父視圖是view controller的view,因為這個view也不能處理事件,因
此傳給view controller,若view controller也不能處理此事件,則傳到window,若
window也不能處理此事件,則傳到app單例對象Application,若UIApplication單
例對象也不能處理,則表示無效事件

initial view一直傳遞直到最上層view, topmost view傳遞事件到它所在的控制器
view controller傳遞事件到topmost view的父視圖,重復(fù)前三步,走到到達(dá)root 
controller由root控制器傳遞事件到window,若window也不能處理此事件,則傳
到app單例對象Application若UIApplication單例對象也不能處理,則表示無效事件

24.什么是 method swizzing ? 講講你的使場景以及使時的注意事項?

Method Swzzling,是指runtime的一個API方法,用于方法交換,使用runtime的
這個交換方法結(jié)合分類category可以改變系統(tǒng)本身的方法,在系統(tǒng)本身方法的基礎(chǔ)上增加代碼操作。
Method swizzing配合類別可以實現(xiàn)在不干擾其它工程代碼的情況下為系統(tǒng)的方法添加功能。
使用runtime的API時,注意調(diào)用順序,一般在 文件的 +load 方法使用。

25.寫個“標(biāo)準(zhǔn)“宏 MIN ,這個宏輸兩個參數(shù)并返回較小的那個?

 #define MIN(A,B) ((A) <= (B) ? (A) : (B))

26.介紹下 layoutSubview 和 drawRect?

UIView的setNeedsDisplay和setNeedsLayout方法。首先兩個方法都是異步執(zhí)
行的。setNeedsDisplay會調(diào)用自動調(diào)用drawRect方法,這樣可以拿到
UIGraphicsGetCurrentContext,就可以畫畫了。而setNeedsLayout會默認(rèn)調(diào)用
layoutSubViews,就可以處理子視圖中的一些數(shù)據(jù)。

layoutSubviews在以下情況下會被調(diào)用:
1、init初始化不會觸發(fā)layoutSubviews。
2、addSubview會觸發(fā)layoutSubviews。
3、設(shè)置view的Frame會觸發(fā)layoutSubviews,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化。
4、滾動一個UIScrollView會觸發(fā)layoutSubviews。
5、旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件。
6、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件。
7、直接調(diào)用setLayoutSubviews。
8、直接調(diào)用setNeedsLayout。

drawRect在以下情況下會被調(diào)用:

1、如果在UIView初始化時沒有設(shè)置rect大小,將直接導(dǎo)致drawRect不被自動調(diào)
用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法
之后掉用的.所以不用擔(dān)心在 控制器中,這些View的drawRect就開始畫了.這樣可
以在控制器中設(shè)置一些值給View
2、該方法在調(diào)用sizeToFit后被調(diào)用,所以可以先調(diào)用sizeToFit計算出size。然
后系統(tǒng)自動調(diào)用drawRect:方法。
3.通過設(shè)置contentMode屬性值為UIViewContentModeRedraw。那么將在每次
設(shè)置或更改frame的時候自動調(diào)用drawRect:。
4、直接調(diào)用setNeedsDisplay,或者setNeedsDisplayInRect:觸發(fā)drawRect:,
但是有個前提條件是rect不能為0。

27.runloop 和線程有什么關(guān)系?

Runloop表示app運行循環(huán)。runloop和線程是緊密相連的,Runloops是線程的
基礎(chǔ)架構(gòu)部分, Cocoa 和 CoreFundation 都提供了 run loop 對象方便配置和
管理線程的 run loop 。每個線程,包括程序的主線程( main thread )都有與
之相應(yīng)的 run loop 對象。
runloop 和線程的關(guān)系:
主線程的run loop默認(rèn)是啟動的。iOS的應(yīng)用程序里面,程序啟動后會有一個
main()函數(shù),UIApplicationMain()函數(shù),這個方法會為main thread設(shè)置一個
NSRunLoop對象,這就解釋了:為什么我們的應(yīng)用可以在無人操作的時候休
息,需要讓它干活的時候又能立馬響應(yīng)。

對其它線程來說,run loop默認(rèn)是沒有啟動的,如果你需要更多的線程交互則可
以手動配置和啟動,如果線程只是去執(zhí)行一個長時間的已確定的任務(wù)則不需要。
可以通過以下代碼來獲取到當(dāng)前線程的 run loop 。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];

28.重寫-個NSString類型的,retain 式聲明name屬性的 setter和getter 法(MRC)

屬性的三大特性:語義特性,原子特性,讀寫特性.
同時重寫setter和getter方法,@synchronized name = _name,關(guān)聯(lián)屬性和實例變量
-(void)setName:(NSString *)name{
    if(_name != name){
      [_name retain];
      [_name release];
      _name = name;
    }
}
-(NSString *)name{
  return [[_name retain] autorelease]
}

29.請用預(yù)處理指令#define聲明一個常數(shù),用以表明1年中有多少秒(忽略閏年問題)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)_U_LONG
#define 語法的基本知識(例如:不能以分號結(jié)束,括號的使用,等等)

30.IBOutlet 連出來的視圖屬性為什么可以被設(shè)置成weak?

因為其父視圖數(shù)組已經(jīng)強(qiáng)引用了。

30.指針與數(shù)組名的關(guān)系?

數(shù)組: 有序的元素序列,數(shù)組名有限個類型相同的變量的集合命名。數(shù)組在內(nèi)
存中所占的大小由數(shù)組長度以及成員類型大小決定。
指針: 又稱指針變量,在32位系統(tǒng)內(nèi)存下占4個byte(64位系統(tǒng)內(nèi)存下占8個
byte),其中保存的值是某一塊內(nèi)存的地址。

31.OC中創(chuàng)建線程的方法是什么? 如果在主線程中執(zhí)行代碼,方法是什么? 如果想延時執(zhí)行代碼,方法是什么?

1.線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建、使用GCD的dispatch、使用子類
化的NSOperation,然后將其加入NSOperationQueue; 
2.在主線程執(zhí)行代碼,方法是performSelectorOnMainThread:withObject:waitUntilDone:; 
3.如果想延時執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone:;

32.堆和棧的區(qū)別

1.棧區(qū)(stack):由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量等值。其
操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)
的內(nèi)存區(qū)域。棧有兩種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完
成的,動態(tài)分配是有alloc函數(shù)進(jìn)行分配的,棧的效率比較高。
2.堆區(qū)(heap):一般由程序員分配釋放,若程序員不釋放,則可能會引起內(nèi)存泄
漏。注 堆和數(shù)據(jù)結(jié)構(gòu)中的堆棧不一樣,其類似于鏈表。堆是向高地址擴(kuò)展的數(shù)
據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。

33.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述?

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

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

@property = ivar + getter + setter;
“屬性” (property)有兩大概念:ivar(實例變量)、存取方法(access method 
= getter + setter)。
“屬性” (property)作為 Objective-C 的一項特性,主要的作用就在于封裝對象中
的數(shù)據(jù)。 Objective-C 對象通常會把其所需要的數(shù)據(jù)保存為各種實例變量。實
例變量一般通過“存取方法”(access method)來訪問。其中,“獲取方法” (getter)
用于讀取變量值,而“設(shè)置方法” (setter)用于寫入變量值。

每次在增加一個屬性,系統(tǒng)都會在 ivar_list 中添加一個成員變量的描述,在 
method_list 中增加 setter 與 getter 方法的描述,在屬性列表中增加一個屬性的
描述,然后計算該屬性在對象中的偏移量,然后給出 setter 與 getter 方法對應(yīng)的
實現(xiàn),在 setter 方法中從偏移量的位置開始賦值,在 getter 方法中從偏移量開始取值

35.聲明的對象有什么特性?

id類型的對象可以是任意類型的OC對象,與C中的void*萬能指針相似。具有運
行時的特點,在程序運行時才確定對象的類型。

36.Objective-C 如何對內(nèi)存管理的,說說你的看法和解決方法?

Objective-C的內(nèi)存管理主要有三種方式ARC(自動內(nèi)存計數(shù))、手動內(nèi)存計數(shù)、內(nèi)存池。
1). 自動內(nèi)存計數(shù):這種方式和java類似,在你的程序的執(zhí)行過程中,你不用考
慮它什么時候開始工作,怎樣工作。
解決:通過alloc – initial方式創(chuàng)建的,創(chuàng)建后引用計數(shù)+1,此后每retain一次引用計
數(shù)+1,那么在程序中做相應(yīng)次數(shù)的release就好了.
2). (NSAutoRealeasePool)內(nèi)存池:可以通過創(chuàng)建和釋放內(nèi)存池控制內(nèi)存申請和回收的時機(jī).
解決:是由autorelease加入系統(tǒng)內(nèi)存池,內(nèi)存池是可以嵌套的,每個內(nèi)存池都需要
有一個創(chuàng)建釋放對,就像main函數(shù)中寫的一樣.使用也很簡單
,比如[[[NSString alloc]initialWithFormat:@”Hey you!”] autorelease],即將一個
NSString對象加入到最內(nèi)層的系統(tǒng)內(nèi)存池,當(dāng)我們釋放這個內(nèi)存池時,其中的對象都會被釋放.

37.Category(類別)、 Extension(擴(kuò)展)和繼承的區(qū)別

1.分類: iOS中,當(dāng)原有類的方法不夠用時,這時候分類就出現(xiàn)了。category是
在現(xiàn)有類的基礎(chǔ)上添加新的方法,利用objective-c 的動態(tài)運行時分配機(jī)制,可
以為現(xiàn)有類添加新方法。可以在分類中添加方法和成員變量,但是添加的成員
變量不會自動生成setter和getter方法,需要在實現(xiàn)部分給出實現(xiàn)。

2.擴(kuò)展: iOS中的extension就是匿名的分類,只有頭文件沒有實現(xiàn)文件。只能
擴(kuò)展方法,不能添加成員變量。擴(kuò)展的方法只能在原類中實現(xiàn)。例如你擴(kuò)展
NSString,那么你只能在NSString的.m實現(xiàn)(這是不可能的),所以盡量少用擴(kuò)
展。用分類就可以了。

3.繼承:學(xué)習(xí)objective-c語言沒有人是不知道繼承,繼承在面向?qū)ο笳Z言是非常
重要的。在iOS中繼承是單繼承,既只能有一個父類。在繼承中,子類可以使用
父類的方法和變量,當(dāng)子類想對本類或者父類的變量進(jìn)行初始化,那么需要重
寫init()方法 。父類也可以訪問子類的方法和成員變量。

38.你是否接觸過OC中的反射機(jī)制?簡單聊一下概念和使用

class反射
    通過類名的字符串形式實例化對象。
        Class class = NSClassFromString(@"student"); 
        Student *stu = [[class alloc] init];
    將類名變?yōu)樽址?        Class class =[Student class];
        NSString *className = NSStringFromClass(class);
SEL的反射
    通過方法的字符串形式實例化方法。
        SEL selector = NSSelectorFromString(@"setName");  
        [stu performSelector:selector withObject:@"Mike"];
    將方法變成字符串。

39.如何對iOS設(shè)備進(jìn)行性能測試?開發(fā)項目時你是怎么檢查內(nèi)存泄露?

1.Profile-> Instruments ->Time Profiler
2.靜態(tài)分析 Analyze。
3.instruments工具里面有個leak可以動態(tài)分析。

40.類變量的 @public,@protected,@private,@package 聲明各有什么含義?

@public 任何地方都能訪問;
@protected 該類和子類中訪問,是默認(rèn)的;
@private 只能在本類中訪問;
@package 本包內(nèi)使用,跨包不可以。

41.什么是謂詞?

謂詞就是通過NSPredicate給定的邏輯條件作為約束條件,完成對數(shù)據(jù)的篩選。
//定義謂詞對象,謂詞對象中包含了過濾條件(過濾條件比較多)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];
//使用謂詞條件過濾數(shù)組中的元素,過濾之后返回查詢的結(jié)果
NSArray *array = [persons filteredArrayUsingPredicate:predicate];

42.isa指針問題

isa:是一個Class 類型的指針. 每個實例對象有個isa的指針,他指向?qū)ο蟮念?而
Class里也有個isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。
當(dāng)類方法被調(diào) 用時,先會從本身查找類方法的實現(xiàn),如果沒有,元類會向他父類查
找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指
針,它的isa指針最終指向的是一個根元類(root meteClass)。根元類的isa指針指
向本身,這樣形成了一個封閉的內(nèi)循環(huán)。

43.iOS中常用的數(shù)據(jù)存儲方式有哪些?

數(shù)據(jù)存儲有四種方案:NSUserDefault、KeyChain、file、DB。
其中File有三種方式:plist、Archive(歸檔)
DB包括:SQLite、FMDB、CoreData

44.iOS的沙盒目錄結(jié)構(gòu)是怎樣的?

1). Application:存放程序源文件,上架前經(jīng)過數(shù)字簽名,上架后不可修改。
2). Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù)。(這里不能存緩存文
件,否則上架不被通過)
3). Library:
        Caches:存放體積大又不需要備份的數(shù)據(jù)。(常用的緩存路徑)
        Preference:設(shè)置目錄,iCloud會備份設(shè)置信息。
4). tmp:存放臨時文件,不會被備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能。

45.dispatch_barrier_async(柵欄函數(shù))的作用是什么?

函數(shù)定義:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
作用:
    1.在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,它后面的任務(wù)要等它執(zhí)行完成后才會開始執(zhí)行。
    2.避免數(shù)據(jù)競爭

46.Runtime實現(xiàn)的機(jī)制是什么,怎么用,一般用于干嘛?

1). 使用時需要導(dǎo)入的頭文件 <objc/message.h>或者<objc/runtime.h>
2). Runtime 運行時機(jī)制,它是一套C語言庫。
3). 實際上我們編寫的所有OC代碼,最終都是轉(zhuǎn)成了runtime庫的東西。
    比如:
        類轉(zhuǎn)成了 Runtime 庫里面的結(jié)構(gòu)體等數(shù)據(jù)類型,
        方法轉(zhuǎn)成了 Runtime 庫里面的C語言函數(shù),
        平時調(diào)方法都是轉(zhuǎn)成了 objc_msgSend 函數(shù)(所以說OC有個消息發(fā)送機(jī)制)
4). 因此,可以說 Runtime 是OC的底層實現(xiàn),是OC的幕后執(zhí)行者。

一般用于:
(1)獲取類里面的所有成員變量。
(2)為類動態(tài)添加成員變量。
(3)動態(tài)改變類的方法實現(xiàn)。
(4)為類動態(tài)添加新的方法等。

47.什么是 Method Swizzle(黑魔法),什么情況下會使用?

1). 在沒有一個類的實現(xiàn)源碼的情況下,想改變其中一個方法的實現(xiàn),除了繼承
它重寫、和借助類別重名方法暴力搶先之外,還有更加靈活的方法 Method Swizzle。
2). Method Swizzle 指的是改變一個已存在的選擇器對應(yīng)的實現(xiàn)的過程。OC中
方法的調(diào)用能夠在運行時通過改變,通過改變類的調(diào)度表中選擇器到最終函數(shù)間的映射關(guān)系。
3). 在OC中調(diào)用一個方法,其實是向一個對象發(fā)送消息,查找消息的唯一依據(jù)
是selector的名字。利用OC的動態(tài)特性,可以實現(xiàn)在運行時偷換selector對應(yīng)的方法實現(xiàn)。
4). 每個類都有一個方法列表,存放著selector的名字和方法實現(xiàn)的映射關(guān)系。
IMP有點類似函數(shù)指針,指向具體的方法實現(xiàn)。
5). 我們可以利用 method_exchangeImplementations 來交換2個方法中的IMP。
6). 我們可以利用 class_replaceMethod 來修改類。
7). 我們可以利用 method_setImplementation 來直接設(shè)置某個方法的IMP。

48._objc_msgForward 函數(shù)是做什么的,直接調(diào)用它將會發(fā)生什么?

_objc_msgForward是 IMP 類型,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個對象發(fā)送一條消
息,但它并沒有實現(xiàn)的時候,_objc_msgForward會嘗試做消息轉(zhuǎn)發(fā)。

49.什么是 TCP / UDP ?

TCP:傳輸控制協(xié)議。
UDP:用戶數(shù)據(jù)協(xié)議。

TCP 是面向連接的,建立連接需要經(jīng)歷三次握手,是可靠的傳輸層協(xié)議。
UDP 是面向無連接的,數(shù)據(jù)傳輸是不可靠的,它只管發(fā),不管收不收得到。
簡單的說,TCP注重數(shù)據(jù)安全,而UDP數(shù)據(jù)傳輸快點,但安全性一般。

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

1.用于向服務(wù)器請求數(shù)據(jù),POST用于提交數(shù)據(jù)
2.GET請求,請求參數(shù)拼接形式暴露在地址欄,而POST請求參數(shù)則放在請求體
里面,因此GET請求不適合用于驗證密碼等操作
3.GET請求的URL有長度限制,POST請求不會有長度限制

51.請簡單的介紹下APNS發(fā)送系統(tǒng)消息的機(jī)制

APNS優(yōu)勢:杜絕了類似安卓那種為了接受通知不停在后臺喚醒程序保持長連
接的行為,由iOS系統(tǒng)和APNS進(jìn)行長連接替代。
APNS的原理:
1). 應(yīng)用在通知中心注冊,由iOS系統(tǒng)向APNS請求返回設(shè)備令牌(device Token)
2). 應(yīng)用程序接收到設(shè)備令牌并發(fā)送給自己的后臺服務(wù)器
3). 服務(wù)器把要推送的內(nèi)容和設(shè)備發(fā)送給APNS
4). APNS根據(jù)設(shè)備令牌找到設(shè)備,再由iOS根據(jù)APPID把推送內(nèi)容展示

52.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:實時監(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解析器;

53.描述下SDWebImage里面給UIImageView加載圖片的邏輯

SDWebImage 中為 UIImageView 提供了一個分類UIImageView+WebCache.h, 
這個分類中有一個最常用的接口sd_setImageWithURL:placeholderImage:,會
在真實圖片出現(xiàn)前會先顯示占位圖片,當(dāng)真實圖片被加載出來后再替換占位圖片。
加載圖片的過程大致如下:
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)用類別的方法:
1. 從內(nèi)存(字典)中找圖片(當(dāng)這個圖片在本次使用程序的過程中已經(jīng)被加載過),找到直接使用。
2. 從沙盒中找(當(dāng)這個圖片在之前使用程序的過程中被加載過),找到使用,緩存到內(nèi)存中。
3. 從網(wǎng)絡(luò)上獲取,使用,緩存到內(nèi)存,緩存到沙盒。

54.不用中間變量,用兩種方法交換 A 和 B 的值?

void swap(int a, int b) {
  a = a + b;
  b = a - b;
  a = a - b;
}

55.求最大公約數(shù)?


/** 1.直接遍歷法 */
int maxCommonDivisor(int a, int b) {
    int max = 0;
    for (int i = 1; i <=b; i++) {
        if (a % i == 0 && b % i == 0) {
            max = i;
        }
    }
    return max;
}

/** 2.輾轉(zhuǎn)相除法 */
int maxCommonDivisor(int a, int b) {
    int r;
    while(a % b > 0) {
        r = a % b;
        a = b;
        b = r;
    }
    return b;
}

56.排序算法?

/** 
 *  【選擇排序】:最值出現(xiàn)在起始端
 *  
 *  第1趟:在n個數(shù)中找到最小(大)數(shù)與第一個數(shù)交換位置
 *  第2趟:在剩下n-1個數(shù)中找到最小(大)數(shù)與第二個數(shù)交換位置
 *  重復(fù)這樣的操作...依次與第三個、第四個...數(shù)交換位置
 *  第n-1趟,最終可實現(xiàn)數(shù)據(jù)的升序(降序)排列。
 *
 */
void selectSort(int *arr, int length) {
    for (int i = 0; i < length - 1; i++) { //趟數(shù)
        for (int j = i + 1; j < length; j++) { //比較次數(shù)
            if (arr[i] > arr[j]) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

/** 
 *  【冒泡排序】:相鄰元素兩兩比較,比較完一趟,最值出現(xiàn)在末尾
 *  第1趟:依次比較相鄰的兩個數(shù),不斷交換(小數(shù)放前,大數(shù)放后)逐個推
進(jìn),最值最后出現(xiàn)在第n個元素位置
 *  第2趟:依次比較相鄰的兩個數(shù),不斷交換(小數(shù)放前,大數(shù)放后)逐個推
進(jìn),最值最后出現(xiàn)在第n-1個元素位置
 *   ……   ……
 *  第n-1趟:依次比較相鄰的兩個數(shù),不斷交換(小數(shù)放前,大數(shù)放后)逐個推
進(jìn),最值最后出現(xiàn)在第2個元素位置 
 */
void bublleSort(int *arr, int length) {
    for(int i = 0; i < length - 1; i++) { //趟數(shù)
        for(int j = 0; j < length - i - 1; j++) { //比較次數(shù)
            if(arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        } 
    }
}

57.折半查找(二分查找)


/**
 *  折半查找:優(yōu)化查找時間(不用遍歷全部數(shù)據(jù))
 *
 *  折半查找的原理:
 *   1> 數(shù)組必須是有序的
 *   2> 必須已知min和max(知道范圍)
 *   3> 動態(tài)計算mid的值,取出mid對應(yīng)的值進(jìn)行比較
 *   4> 如果mid對應(yīng)的值大于要查找的值,那么max要變小為mid-1
 *   5> 如果mid對應(yīng)的值小于要查找的值,那么min要變大為mid+1
 *
 */ 
 
// 已知一個有序數(shù)組, 和一個key, 要求從數(shù)組中找到key對應(yīng)的索引位置 
int findKey(int *arr, int length, int key) {
    int min = 0, max = length - 1, mid;
    while (min <= max) {
        mid = (min + max) / 2; //計算中間值
        if (key > arr[mid]) {
            min = mid + 1;
        } else if (key < arr[mid]) {
            max = mid - 1;
        } else {
            return mid;
        }
    }
    return -1;
}

58.避免使用C語言中的基本數(shù)據(jù)類型,建議使用 Foundation 數(shù)據(jù)類型,對應(yīng)關(guān)系?

int -> NSInteger
unsigned -> NSUInteger
float -> CGFloat
動畫時間 -> NSTimeInterval 等

59 如何讓計時器調(diào)用一個類方法

計時器只能調(diào)用實例方法,但是可以在這個實例方法里面調(diào)用靜態(tài)方法。
使用計時器需要注意,計時器一定要加入RunLoop中,并且選好model才能運
行。scheduledTimerWithTimeInterval方法創(chuàng)建一個計時器并加入到RunLoop中
所以可以直接使用。
如果計時器的repeats選擇YES說明這個計時器會重復(fù)執(zhí)行,一定要在合適的時
機(jī)調(diào)用計時器的invalid。不能在dealloc中調(diào)用,因為一旦設(shè)置為repeats 為
yes,計時器會強(qiáng)持有self,導(dǎo)致dealloc永遠(yuǎn)不會被調(diào)用,這個類就永遠(yuǎn)無法被
釋放。比如可以在viewDidDisappear中調(diào)用,這樣當(dāng)類需要被回收的時候就可
以正常進(jìn)入dealloc中了。

60.id和NSObject*的區(qū)別

id是一個 objc_object 結(jié)構(gòu)體指針,定義是 typedef struct objc_object *id
id可以理解為指向?qū)ο蟮闹羔?。所有oc的對象 id都可以指向,編譯器不會做類
型檢查,id調(diào)用任何存在的方法都不會在編譯階段報錯,當(dāng)然如果這個id指向的
對象沒有這個方法,該崩潰還是會崩潰的。
 
NSObject *指向的必須是NSObject的子類,調(diào)用的也只能是NSObjec里面的方
法否則就要做強(qiáng)制類型轉(zhuǎn)換。
 
不是所有的OC對象都是NSObject的子類,還有一些繼承自NSProxy。
NSObject *可指向的類型是id的子集。

61.你實現(xiàn)過一個框架或者庫以供別人使用么?如果有,請談一談構(gòu)建框架或者庫時候的經(jīng)驗;如果沒有,請設(shè)想和設(shè)計框架的public的API,并指出大概需要如何做、需要注意一些什么方面,來使別人容易地使用你的框架。

抽象和封裝,方便使用。首先是對問題有充分的了解,比如構(gòu)建一個文件解壓
壓縮框架,從使用者的角度出發(fā),只需關(guān)注發(fā)送給框架一個解壓請求,框架完
成復(fù)雜文件的解壓操作,并且在適當(dāng)?shù)臅r候通知給是哦難過者,如解壓完成、
解壓出錯等。在框架內(nèi)部去構(gòu)建對象的關(guān)系,通過抽象讓其更為健壯、便于更
改。其次是API的說明文檔。

62.對于Objective-C,你認(rèn)為它最大的優(yōu)點和最大的不足是什么?對于不足之處,現(xiàn)在有沒有可用的方法繞過這些不足來實現(xiàn)需求。

最大的優(yōu)點是它的運行時特性,不足是沒有命名空間,對于命名沖突,可以使
用長命名法或特殊前綴解決,如果是引入的第三方庫之間的命名沖突,可以使
用link命令及flag解決沖突。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,680評論 1 32
  • 導(dǎo) 語 但她更是鬧得不可開交:“就是要出去,你想困死我嗎?我生的可是兒子,你還有什么不滿意的?”得,搬兒子出來說事...
    飄雨桐V閱讀 332評論 0 0
  • 4K大尺寸彩鉛~喜歡的朋友可以約我看原圖~有需要也可以幫畫嘻嘻(˙︶˙)
    喵喵醬畫彩鉛閱讀 534評論 6 9

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