iOS問答 - 2

目錄

1.解釋self = [super init]方法
2.網(wǎng)絡(luò)七層協(xié)議
3.OC中是否有二維數(shù)組,如何實(shí)現(xiàn)二維數(shù)組
4.@synthesize、@dynamic的理解
5.XIB與Storyboards及純代碼的優(yōu)缺點(diǎn)
6.內(nèi)存的使用和優(yōu)化的注意事項(xiàng)
7.pushViewController、presentViewController原理及區(qū)別.
8.發(fā)現(xiàn)VC不走dealloc,如何檢查原因。
9. 什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?
10. objc中的類方法和實(shí)例方法有什么本質(zhì)區(qū)別和聯(lián)系?
11. _objc_msgForward函數(shù)是做什么的,直接調(diào)用它將會(huì)發(fā)生什么?
12.__block和__weak修飾符的區(qū)別:
13.iOS 中的事件的傳遞:響應(yīng)鏈
14.應(yīng)用程序的生命周期
15.動(dòng)畫原理與實(shí)現(xiàn)
16.類結(jié)構(gòu)體的組成,isa指針指向了什么?
17.RunLoop有幾種事件源?有幾種模式?
18.lldb(gdb)常用的調(diào)試命令?
19.performSelector延時(shí)調(diào)用導(dǎo)致的內(nèi)存泄露?
20.如何對(duì)真機(jī)的crash日志進(jìn)行分析?
21.對(duì)象回收時(shí)Weak指針自動(dòng)被置為nil的實(shí)現(xiàn)原理
22.遠(yuǎn)程推送
23.熱修復(fù)
24.組件化開發(fā)
25.Instruments性能檢測(cè)
26.加密
27.優(yōu)化CPU消耗
28.單例
29.Objective-C堆和棧的區(qū)別?
30.關(guān)鍵字const有什么含意?修飾類呢?static的作用,用于類呢?還有extern c的作用
31.關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子。
32. 一個(gè)參數(shù)既可以是const還可以是volatile嗎? 一個(gè)指針可以是volatile 嗎?解釋為什么。
33.static 關(guān)鍵字的作用:
34.線程與進(jìn)程的區(qū)別和聯(lián)系?
35.列舉幾種進(jìn)程的同步機(jī)制,并比較其優(yōu)缺點(diǎn)。
36. 進(jìn)程之間通信的途徑
37. 進(jìn)程死鎖的原因
38. 死鎖的4個(gè)必要條件
39. 死鎖的處理
40.cocoa touch框架
41.自動(dòng)釋放池是什么,如何工作
42. Objective-C的優(yōu)缺點(diǎn)。
43.sprintf,strcpy,memcpy使用上有什么要注意的地方。
44.http和scoket通信的區(qū)別。
45.TCP和UDP的區(qū)別
46.請(qǐng)簡(jiǎn)要說明viewDidLoad和viewDidUnload何時(shí)調(diào)用
47. 簡(jiǎn)述內(nèi)存分區(qū)情況
48.隊(duì)列和棧有什么區(qū)別:
49.HTTP協(xié)議中,POST和GET的區(qū)別是什么?
50.iOS的系統(tǒng)架構(gòu)

1.解釋self = [super init]方法

容錯(cuò)處理,當(dāng)父類初始化失敗,會(huì)返回一個(gè)nil,表示初始化失敗。由于繼承的關(guān)系,子類是需要擁有父類的實(shí)例和行為,因此,我們必須先初始化父類,然后再初始化子類

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

應(yīng)用層:
1.用戶接口、應(yīng)用程序;
2.Application典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TELNET、FTP、HTTP
表示層:
1.數(shù)據(jù)表示、壓縮和加密presentation
2.典型設(shè)備:網(wǎng)關(guān)
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:ASCLL、PICT、TIFF、JPEG|MPEG
4.表示層相當(dāng)于一個(gè)東西的表示,表示的一些協(xié)議,比如圖片、聲音和視頻MPEG。
會(huì)話層:
1.會(huì)話的建立和結(jié)束;
2.典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:RPC、SQL、NFS、X WINDOWS、ASP
傳輸層:
1.主要功能:端到端控制Transport;
2.典型設(shè)備:網(wǎng)關(guān);
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TCP、UDP、SPX
網(wǎng)絡(luò)層:
1.主要功能:路由、尋址Network;
2.典型設(shè)備:路由器;
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:IP、IPX、APPLETALK、ICMP;
數(shù)據(jù)鏈路層:
1.主要功能:保證無差錯(cuò)的疏忽鏈路的data link;
2.典型設(shè)備:交換機(jī)、網(wǎng)橋、網(wǎng)卡;
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:802.2、802.3ATM、HDLC、FRAME RELAY;
物理層:
1.主要功能:傳輸比特流Physical;
2.典型設(shè)備:集線器、中繼器
3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:V.35、EIA/TIA-232.

3.OC中是否有二維數(shù)組,如何實(shí)現(xiàn)二維數(shù)組

OC中沒有二維數(shù)組,可通過嵌套數(shù)組實(shí)現(xiàn)二維數(shù)組。

4.@synthesize、@dynamic的理解

@synthesize是系統(tǒng)自動(dòng)生成getter和setter屬性聲明;@synthesize的意思是,除非開發(fā)人員已經(jīng)做了,否則由編譯器生成相應(yīng)的代碼,以滿足屬性聲明;
@dynamic是開發(fā)者自已提供相應(yīng)的屬性聲明,@dynamic意思是由開發(fā)人員提供相應(yīng)的代碼:對(duì)于只讀屬性需要提供setter,對(duì)于讀寫屬性需要提供 setter 和getter。查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由用戶自己實(shí)現(xiàn), 不自動(dòng)生成。

5.XIB與Storyboards及純代碼的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):
XIB:在編譯前就提供了可視化界面,可以直接拖控件,也可以直接給控件添加約束,更直觀一些,而且類文件中就少了創(chuàng)建控件的代碼,確實(shí)簡(jiǎn)化不少,通常每個(gè)XIB對(duì)應(yīng)一個(gè)類。
Storyboard:在編譯前提供了可視化界面,可拖控件,可加約束,在開發(fā)時(shí)比較直觀,而且一個(gè)storyboard可以有很多的界面,每個(gè)界面對(duì)應(yīng)一個(gè)類文件,通過storybard,可以直觀地看出整個(gè)App的結(jié)構(gòu)。
缺點(diǎn):
XIB:需求變動(dòng)時(shí),需要修改XIB很大,有時(shí)候甚至需要重新添加約束,導(dǎo)致開發(fā)周期變長(zhǎng)。XIB載入相比純代碼自然要慢一些。對(duì)于比較復(fù)雜邏輯控制不同狀態(tài)下顯示不同內(nèi)容時(shí),使用XIB是比較困難的。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時(shí),如果XIB文件被發(fā)動(dòng),極易導(dǎo)致沖突,而且解決沖突相對(duì)要困難很多。
Storyboard:需求變動(dòng)時(shí),需要修改storyboard上對(duì)應(yīng)的界面的約束,與XIB一樣可能要重新添加約束,或者添加約束會(huì)造成大量的沖突,尤其是多團(tuán)隊(duì)開發(fā)。對(duì)于復(fù)雜邏輯控制不同顯示內(nèi)容時(shí),比較困難。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時(shí),大家會(huì)同時(shí)修改一個(gè)storyboard,導(dǎo)致大量沖突,解決起來相當(dāng)困難。

手寫代碼:
優(yōu)勢(shì):適合大型項(xiàng)目大規(guī)模使用,利于版本管理、追蹤改動(dòng)以及代碼合并;最好的代碼重用性
劣勢(shì):慢,開發(fā)周期長(zhǎng),維護(hù)代碼復(fù)雜;自動(dòng)布局AutoLayout困難
xib:
優(yōu)勢(shì):開發(fā)速度快;在版本管理上和純代碼的差異并不是很大,易讀易維護(hù)
劣勢(shì):xib中的設(shè)置往往并非最終設(shè)置,UI設(shè)計(jì)會(huì)被代碼所覆蓋;
storyboard:
優(yōu)勢(shì):可以看到每個(gè)ViewController的布局樣式,也可以明確地知道各個(gè)ViewController之間的轉(zhuǎn)換關(guān)系;代碼量少,開發(fā)周期短;關(guān)鍵是已經(jīng)成為新建項(xiàng)目時(shí)候的默認(rèn)配置,代表著蘋果以后的方向和重心
劣勢(shì):很難多人協(xié)作;ViewController的重用和自定義的view的處理;

6.內(nèi)存的使用和優(yōu)化的注意事項(xiàng)

  • 重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設(shè)置正確的reuseIdentifier,充分重用;
  • 盡量把views設(shè)置為不透明:當(dāng)opque為NO的時(shí)候,圖層的半透明取決于圖片和其本身合成的圖層為結(jié)果,可提高性能;
  • 不要使用太復(fù)雜的XIB/Storyboard:載入時(shí)就會(huì)將XIB/storyboard需要的所有資源,包括圖片全部載入內(nèi)存,即使未來很久才會(huì)使用。那些相比純代碼寫的* 延遲加載,性能及內(nèi)存就差了很多;
  • 選擇正確的數(shù)據(jù)結(jié)構(gòu):學(xué)會(huì)選擇對(duì)業(yè)務(wù)場(chǎng)景最合適的數(shù)組結(jié)構(gòu)是寫出高效代碼的基礎(chǔ)。比如,數(shù)組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲(chǔ)鍵值對(duì),用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。
  • gzip/zip壓縮:當(dāng)從服務(wù)端下載相關(guān)附件時(shí),可以通過gzip/zip壓縮后再下載,使得內(nèi)存更小,下載速度也更快。
  • 延遲加載:對(duì)于不應(yīng)該使用的數(shù)據(jù),使用延遲加載方式。對(duì)于不需要馬上顯示的視圖,使用延遲加載方式。比如,網(wǎng)絡(luò)請(qǐng)求失敗時(shí)顯示的提示界面,可能一直都不會(huì)使用到,因此應(yīng)該使用延遲加載。
  • 數(shù)據(jù)緩存:對(duì)于cell的行高要緩存起來,使得reload數(shù)據(jù)時(shí),效率也極高。而對(duì)于那些網(wǎng)絡(luò)數(shù)據(jù),不需要每次都請(qǐng)求的,應(yīng)該緩存起來,可以寫入數(shù)據(jù)庫,也可以通過plist文件存儲(chǔ)。
  • 處理內(nèi)存警告:一般在基類統(tǒng)一處理內(nèi)存警告,將相關(guān)不用資源立即釋放掉
  • 重用大開銷對(duì)象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它們。通常是作為屬性存儲(chǔ)起來,防止反復(fù)創(chuàng)建。
  • 避免反復(fù)處理數(shù)據(jù):許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)。在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要;
  • 使用Autorelease Pool:在某些循環(huán)創(chuàng)建臨時(shí)變量處理數(shù)據(jù)時(shí),自動(dòng)釋放池以保證能及時(shí)釋放內(nèi)存;
  • 正確選擇圖片加載方式

7.pushViewController、presentViewController原理及區(qū)別.

區(qū)別:present只能逐級(jí)返回,push所有視圖由視圖棧控制,可以返回上一級(jí),也可以返回到根vc,其他vc。present一般用于不同業(yè)務(wù)界面的切換,push一般用于同一業(yè)務(wù)不同界面之間的切換。

8.發(fā)現(xiàn)VC不走dealloc,如何檢查原因。

在一個(gè)項(xiàng)目中,如果ViewController使用完成之后,發(fā)現(xiàn)這個(gè)東東并沒有釋放掉,dealloc方法不走,看著那個(gè)內(nèi)存蹭蹭的網(wǎng)上增,相信大家都知道如何去釋放一個(gè)不用的ViewController,但是還是有些其他因素限制了內(nèi)存釋放。

如果你的VC中有NSTimer,那么就要注意了,因?yàn)楫?dāng)你[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];時(shí),這個(gè) target:self 就增加了VC的RetarnCountr如果你不將這個(gè)timer invalidate,就別想調(diào)用dealloc。

再然后,一個(gè)比較隱蔽的因素,你反過頭去找找看,跟這個(gè)類有關(guān)的代理,嗯,對(duì)是代理,有沒有強(qiáng)引用的屬性???對(duì),比如一個(gè)代理的delegate應(yīng)

該是 assign 的現(xiàn)在是retain,就是這個(gè),它會(huì)影響你不讓你調(diào)用dealloc,不信,就試試吧。

最后,如果以上都沒有問題的話,那么,真問題就來了。我就遇到了這種情況,在使用ASI進(jìn)行網(wǎng)絡(luò)請(qǐng)求的時(shí)候,因?yàn)樾枨笤?,我使用屬性將名為ASIFormDataRequest 的NSOperation 標(biāo)記住了,就將上面的問題找了又找,就是不行,最后是將那個(gè)標(biāo)記的屬性置為 nil,才解決了這個(gè)不調(diào)用 dealloc的這個(gè)蛋疼問題。所以,如果你遇到了比較隱蔽的原因,那就去找找你自己控制不了的因素,就像這個(gè)第三方。如果你不了解它的運(yùn)行機(jī)制,那就一定要注意這個(gè)庫

PS:dealloc中的釋放也是有順序的,就好比創(chuàng)建時(shí),先父類,再子類,釋放的時(shí)候反過來,不然有幾率會(huì)crash,至于原因。 子類是父類的繼承,比較NB,以至于要?dú)⑺浪麄兊臅r(shí)候應(yīng)該先干掉比較牛B的子類。

9. 什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?

什么情況使用 weak 關(guān)鍵字?
1)在ARC中,在有可能出現(xiàn)循環(huán)引用的時(shí)候,往往要通過讓其中一端使用weak來解決,比如:delegate代理屬性
2)自身已經(jīng)對(duì)它進(jìn)行一次強(qiáng)引用,沒有必要再?gòu)?qiáng)引用一次,此時(shí)也會(huì)使用weak,自定義IBOutlet控件屬性一般也使用weak;當(dāng)然,也可以使用strong。在下文也有論述:《IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak?》
不同點(diǎn):
1)weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)。為這種屬性設(shè)置新值時(shí),設(shè)置方法既不保留新值,也不釋放舊值。此特質(zhì)同assign類似, 然而在屬性所指的對(duì)象遭到摧毀時(shí),屬性值也會(huì)清空(nil out)。 而 assign 的“設(shè)置方法”只會(huì)執(zhí)行針對(duì)“純量類型” (scalar type,例如 CGFloat 或 NSlnteger 等)的簡(jiǎn)單賦值操作。
2)assigin 可以用非OC對(duì)象,而weak必須用于OC對(duì)象

10. objc中的類方法和實(shí)例方法有什么本質(zhì)區(qū)別和聯(lián)系?

類方法:
類方法是屬于類對(duì)象的
類方法只能通過類對(duì)象調(diào)用
類方法中的self是類對(duì)象
類方法可以調(diào)用其他的類方法
類方法中不能訪問成員變量
類方法中不能直接調(diào)用對(duì)象方法

實(shí)例方法:
實(shí)例方法是屬于實(shí)例對(duì)象的
實(shí)例方法只能通過實(shí)例對(duì)象調(diào)用
實(shí)例方法中的self是實(shí)例對(duì)象
實(shí)例方法中可以訪問成員變量
實(shí)例方法中直接調(diào)用實(shí)例方法
實(shí)例方法中也可以調(diào)用類方法(通過類名)

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

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

12.__block和__weak修飾符的區(qū)別:

__block不管是ARC還是MRC模式下都可以使用,可以修飾對(duì)象,還可以修飾基本數(shù)據(jù)類型。
__weak只能在ARC模式下使用,也只能修飾對(duì)象(NSString),不能修飾基本數(shù)據(jù)類型(int)。
__block對(duì)象可以在block中被重新賦值,__weak不可以。

13.iOS 中的事件的傳遞:響應(yīng)鏈

簡(jiǎn)要說一下:
事件沿著一個(gè)指定的路徑傳遞直到它遇見可以處理它的對(duì)象。 首先一個(gè)UIApplication 對(duì)象從隊(duì)列頂部獲取一個(gè)事件并分發(fā)(dispatches)它以便處理。 通常,它把事件傳遞給應(yīng)用程序的關(guān)鍵窗口對(duì)象,該對(duì)象把事件傳遞給一個(gè)初始對(duì)象來處理。 初始對(duì)象取決于事件的類型。

觸摸事件。 對(duì)于觸摸事件,窗口對(duì)象首先嘗試把事件傳遞給觸摸發(fā)生的視圖。那個(gè)視圖被稱為hit-test(點(diǎn)擊測(cè)試)視圖。 尋找hit-test視圖的過程被稱為hit-testing, 參見 “Hit-Testing Returns the View Where a Touch Occurred.”

運(yùn)動(dòng)和遠(yuǎn)程控制事件。 對(duì)于這些事件,窗口對(duì)象把shaking-motion(搖晃運(yùn)動(dòng))或遠(yuǎn)程控制事件傳遞給第一響應(yīng)者來處理。第一響應(yīng)者請(qǐng)參見 “The Responder Chain Is Made Up of Responder Objects.”

iOS 使用hit-testing來找到事件發(fā)生的視圖。 Hit-testing包括檢查觸摸事件是否發(fā)生在任何相關(guān)視圖對(duì)象的范圍內(nèi), 如果是,則遞歸地檢查所有視圖的子視圖。在視圖層次中的最底層視圖,如果它包含了觸摸點(diǎn),那么它就是hit-test視圖。等 iOS決定了hit-test視圖之后,它把觸摸事件傳遞給該視圖以便處理。

14.應(yīng)用程序的生命周期

一個(gè)應(yīng)用程序有五種狀態(tài):

  • Not running 未運(yùn)行 ,程序沒啟動(dòng)。
  • Inactive 未激活 ,程序在前臺(tái)運(yùn)行,沒有接收到事件。在程序沒有事件需要處理時(shí)停留在這個(gè)狀態(tài)。
  • Active 激活,程序在前臺(tái)運(yùn)行而且接收到了事件。這也是前臺(tái)的一個(gè)正常的模式
  • Backgroud 后臺(tái),程序在后臺(tái)而且能執(zhí)行代碼,大多數(shù)程序只能短暫停留這個(gè)狀態(tài),馬上進(jìn)入Suspended狀態(tài)。
  • Suspended 掛起,程序在后臺(tái)不能執(zhí)行代碼。但程序不會(huì)被馬上殺死,當(dāng)系統(tǒng)內(nèi)存不足時(shí),在這個(gè)狀態(tài)的程序占用的內(nèi)存優(yōu)先被回收。

切換狀態(tài)時(shí)的回調(diào):
在發(fā)生狀態(tài)切換時(shí),都會(huì)調(diào)用delegate對(duì)象對(duì)應(yīng)的方法來響應(yīng)App狀態(tài)的改變。

  • application:willFinishLaunchingWithOptions: 這個(gè)方法是你在啟動(dòng)時(shí)的第一次機(jī)會(huì)來執(zhí)行代碼
  • application:didFinishLaunchingWithOptions: 這個(gè)方法允許你在顯示app給用戶之前執(zhí)行最后的初始化操作
  • applicationDidBecomeActive: app已經(jīng)切換到active狀態(tài)后需要執(zhí)行的操作
  • applicationWillResignActive: app將要從前臺(tái)切換到后臺(tái)時(shí)需要執(zhí)行的操作
  • applicationDidEnterBackground: app已經(jīng)進(jìn)入后臺(tái)后需要執(zhí)行的操作
  • applicationWillEnterForeground: app將要從后臺(tái)切換到前臺(tái)需要執(zhí)行的操作,但app還不是active狀態(tài)
  • applicationWillTerminate: app將要結(jié)束時(shí)需要執(zhí)行的操作

接下來是App啟動(dòng)、切換和鎖屏狀態(tài)時(shí)調(diào)用delegate對(duì)象的方法

  • App啟動(dòng)
    App啟動(dòng)時(shí),首先由not running狀態(tài)切換到inactive狀態(tài),此時(shí)調(diào)用application:didFinishLaunchingWithOptions:方法;然后調(diào)用application:didFinishLaunchingWithOptions:方法,最后由inactive狀態(tài)切換到active狀態(tài),此時(shí)調(diào)用applicationDidBecomeActive:方法。
  • App無事件響應(yīng)
    由active狀態(tài)切換到inactive狀態(tài),此時(shí)調(diào)用applicationWillResignActive:方法。
  • 切換App
    當(dāng)切換到另一個(gè)App時(shí),由狀態(tài)active切換到inactive,此時(shí)調(diào)用applicationWillResignActive:方法;然后從inactive狀態(tài)切換到running(background)狀態(tài),此時(shí)調(diào)用applicationDidEnterBackground:方法。
  • 鎖屏
    當(dāng)手機(jī)鎖屏?xí)r,由狀態(tài)active切換到inactive,此時(shí)調(diào)用applicationWillResignActive:;然后再由inactive狀態(tài)切換到running(background)狀態(tài),此時(shí)調(diào)用applicationDidEnterBackground:方法。
  • App響應(yīng)中斷
    當(dāng)一個(gè)基于警告式的中斷發(fā)生時(shí),比如有電話打進(jìn)來了,這是程序會(huì)臨時(shí)進(jìn)入inactive狀態(tài),這用戶可以選擇如何處理這個(gè)中斷。接著會(huì)調(diào)用applicationWillResignActive:方法,當(dāng)中斷來臨時(shí),你需要在這個(gè)方法中,停止timer或者周期性任務(wù)、停止視頻,音樂播放、停止游戲運(yùn)行。當(dāng)程序回到active狀態(tài) , applicationDidBecomeActive: 會(huì)調(diào)用方法,恢復(fù)停止的操作。
  • App轉(zhuǎn)到后臺(tái)運(yùn)行
    首先調(diào)用applicationWillResignActive:方法,程序即將進(jìn)入后臺(tái)運(yùn)行,接著調(diào)用applicationDidEnterBackground: 方法,此時(shí)程序?yàn)閎ackground狀態(tài),系統(tǒng)允許程序繼續(xù)運(yùn)行一段時(shí)間,然后程序進(jìn)入Suspended狀態(tài)。
  • App轉(zhuǎn)到前臺(tái)運(yùn)行
    系統(tǒng)喚醒程序,調(diào)用applicationWillEnterForeground: 方法,程序從background狀態(tài)改為active狀態(tài),接著調(diào)用applicationDidBecomeActive:方法。當(dāng)app處于掛起狀態(tài)時(shí),它是不能執(zhí)行任何代碼的。因此它不能處理在掛起期間發(fā)過來的通知,比如方向改變,時(shí)間改變,設(shè)置的改變還有其他影響程序展現(xiàn)的或狀態(tài)的通知。在程序返回后臺(tái)或前臺(tái)時(shí),程序要正確的處理這些通知。
  • App終止
    當(dāng)App被系統(tǒng)終止(如內(nèi)存不足、Crash)或者用戶自行終止。系統(tǒng)會(huì)在應(yīng)用程序終止之前調(diào)用applicationWillTerminate: 方法,來保存用戶的一些重要數(shù)據(jù)以便下次啟動(dòng)時(shí)恢復(fù)到app原來的狀態(tài)。

15.動(dòng)畫原理與實(shí)現(xiàn)

動(dòng)畫的實(shí)現(xiàn)
我們也可將 iOS 的動(dòng)畫分為兩大類:
系統(tǒng)提供的 關(guān)鍵幀動(dòng)畫 實(shí)現(xiàn)方式;用戶指定 關(guān)鍵 信息,系統(tǒng)實(shí)現(xiàn)動(dòng)畫過程,對(duì)用戶而言操作起來會(huì)簡(jiǎn)單些。
逐幀動(dòng)畫 實(shí)現(xiàn)方式;用戶自己 畫 出每一幀畫面,系統(tǒng)操作方法簡(jiǎn)單,但用戶操作的工作量就會(huì)大一些。

逐幀動(dòng)畫實(shí)現(xiàn)方式

簡(jiǎn)單的說,要實(shí)現(xiàn)逐幀的方式,就是需要 周期性 的調(diào)用 繪制 方法,繪制每幀的動(dòng)畫對(duì)象。
這里說的 繪制,不光是指覆寫 UIView 的 - drawRect:的方法來手動(dòng)重繪視圖,也包括修改 UIView 它的屬性,比如位置、顏色等。
iOS 的動(dòng)畫都是基于 CALayer 的,iOS 的 UIView 背后都有一個(gè)對(duì)應(yīng)的 CALayer 。對(duì) UIView 的修改實(shí)際上都是對(duì)背后 CALayer 的修改。
但如果在逐幀繪制的方法中修改了一個(gè)自建的 CALayer,這個(gè) CALayer 不是對(duì)應(yīng)某個(gè) UIView 的,需注意系統(tǒng)的 隱式動(dòng)畫 的影響,后面會(huì)提到這點(diǎn)。
而 周期性,就需要一個(gè)定時(shí)器來完成了,即 CADisplayLink。
CADisplayLink 與 NSTimer 比較類似,可以周期性的調(diào)用指定的方法。
之所以用 CADisplayLink,是因?yàn)樗腔谄聊凰⑿侣实模雌聊幻看嗡⑿聲r(shí)就會(huì)觸發(fā)調(diào)用。
iPhone 的屏幕刷新率是 60 FPS。

關(guān)鍵幀動(dòng)畫實(shí)現(xiàn)方式

采用關(guān)鍵幀的方式來實(shí)現(xiàn)動(dòng)畫,要講的內(nèi)容相對(duì)逐幀的方式就多的多了。
還是用 UIView 移動(dòng)的簡(jiǎn)單例子。
這里面有兩個(gè)關(guān)鍵幀,起始幀和結(jié)束幀,除此之外還有2個(gè)關(guān)鍵信息:
起始幀,變化信息:坐標(biāo)為 (0,0)
結(jié)束幀,變化信息:坐標(biāo)為 (100,0)
動(dòng)畫時(shí)間,0.25秒
勻速運(yùn)動(dòng)
坐標(biāo) 信息是 UIView 的一個(gè)屬性(實(shí)際是對(duì)應(yīng)到 CALayer 的屬性),在動(dòng)畫實(shí)現(xiàn)里,我們只需要指定起始和結(jié)束的兩個(gè)關(guān)鍵值就夠了,中間的過渡值都有系統(tǒng)自動(dòng)生成。
這里出現(xiàn)了兩種值,一個(gè)是我們?cè)O(shè)定的,一個(gè)是系統(tǒng)生成的,所以要先在這里插入一個(gè) 模型層 和 展現(xiàn)層 的概念了
CALayer 的同一個(gè)屬性值,會(huì)分別保存在模型層 modelLayer ,和展現(xiàn)層 presentationLayer 中。當(dāng)我們修改屬性值時(shí),是修改的模型層的數(shù)值,動(dòng)畫時(shí)系統(tǒng)根據(jù)模型層的變化,生成的過渡值,是保存在展現(xiàn)層中的。
在 CALayer 的對(duì)象里能直接訪問到這兩層的信息。
而 CALayer 的底層實(shí)現(xiàn)實(shí)際不止這兩層,但我們現(xiàn)在討論動(dòng)畫的時(shí)候,可以只關(guān)心這兩層。

動(dòng)畫實(shí)現(xiàn)

將動(dòng)畫加入 CALayer 的代碼定義為:

- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key

接受的類型是 CAAnimation 類型,有下面這些子類:
CABasicAnimation,可設(shè)定起始結(jié)束兩個(gè)關(guān)鍵幀的信息。
CAKeyframeAnimation,除首尾外,還可添加多個(gè)中間關(guān)鍵點(diǎn)。
CAAnimationGroup ,可組合多個(gè)動(dòng)畫,因?yàn)樯厦鎯煞N動(dòng)畫一次只能設(shè)置一個(gè)屬性值。
CATransition,圖層過渡動(dòng)畫,默認(rèn)是淡入。比如修改一個(gè) CALayer的背景色時(shí),是從初始色慢慢淡入過渡到結(jié)束色。
可修改為新顏色把舊顏色頂出去等效果。還可使用 CIFilter 濾鏡做過渡效果,一些開源 UIViewController 的過渡動(dòng)畫使用了這種方式。
動(dòng)畫中,除了屬性值外,我們還設(shè)置了兩個(gè)和時(shí)間有關(guān)的信息:動(dòng)畫時(shí)間0.25秒,運(yùn)動(dòng)方式是勻速運(yùn)動(dòng)。
動(dòng)畫持續(xù)時(shí)間很簡(jiǎn)單,是通過 CAAnimation 遵守的 CAMediaTiming 協(xié)議設(shè)定的。
勻速運(yùn)動(dòng)是通過設(shè)置 CAAnimation 的 timingFunction 實(shí)現(xiàn)的,這是一個(gè) CAMediaTimingFunction 類的對(duì)象。

隱式動(dòng)畫

上面的過程,我們是 顯式 的向一個(gè) CALayer 添加了一個(gè)動(dòng)畫,所以這種方式叫做 顯式動(dòng)畫。
對(duì)應(yīng)的,還有 隱式動(dòng)畫,即系統(tǒng)自動(dòng)添加上的動(dòng)畫。

    CALayer *layer = [CALayer layer];
    layer.backgroundColor = [UIColor greenColor].CGColor;
    layer.frame = CGRectMake(0, 0, 100, 100);
    [self.view.layer addSublayer:layer];
    layer.frame = CGRectOffset(layer.frame, 100, 0);

這段代碼里,我們沒有添加 CAAnimation 動(dòng)畫,但 layer 不是直接變化到新的位置,而是有一個(gè)動(dòng)畫效果。
這就是 隱式動(dòng)畫 的效果。

動(dòng)畫事務(wù)

創(chuàng)建動(dòng)畫事務(wù)的目的是為了操作的原子性,保證動(dòng)畫的所有修改能同時(shí)生效。
CATransaction 就是動(dòng)畫事務(wù)的操作類。
在創(chuàng)建隱式動(dòng)畫的時(shí)候,系統(tǒng)也會(huì)隱式的創(chuàng)建一個(gè)動(dòng)畫事務(wù),以保證所有的動(dòng)畫能同時(shí)進(jìn)行。
除此之外,還可以顯式的創(chuàng)建一個(gè)事務(wù)。
顯式事務(wù)中可以定義事務(wù)中所有動(dòng)畫的運(yùn)行時(shí)間和時(shí)間函數(shù),此外,還有這個(gè)方法 + (void)setDisableActions:(BOOL)flag 能顯式的關(guān)閉這個(gè)事務(wù)中的 action 查詢操作。
關(guān)閉了查詢也就是關(guān)閉了動(dòng)畫效果,屬性值的變化就會(huì)立即生效,而沒有動(dòng)畫效果了:

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    ///...
    layer.frame = CGRectOffset(layer.frame, 100, 0);
    ///...
    [CATransaction commit];

16.類結(jié)構(gòu)體的組成,isa指針指向了什么?

在Objective-C中,任何類的定義都是對(duì)象。類和類的實(shí)例(對(duì)象)沒有任何本質(zhì)上的區(qū)別。任何對(duì)象都有isa指針。
Class 是一個(gè) objc_class 結(jié)構(gòu)類型的指針, id是一個(gè) objc_object 結(jié)構(gòu)類型的指針.

objc_class 的定義:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

各個(gè)參數(shù)的意思:
isa:是一個(gè)Class 類型的指針. 每個(gè)實(shí)例對(duì)象有個(gè)isa的指針,他指向?qū)ο蟮念?,而Class里也有個(gè)isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。當(dāng)類方法被調(diào)用時(shí),先會(huì)從本身查找類方法的實(shí)現(xiàn),如果沒有,元類會(huì)向他父類查找該方法。同時(shí)注意的是:元類(meteClass)也是類,它也是對(duì)象。元類也有isa指針,它的isa指針最終指向的是一個(gè)根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個(gè)封閉的內(nèi)循環(huán)。
super_class:父類,如果該類已經(jīng)是最頂層的根類,那么它為NULL。
version:類的版本信息,默認(rèn)為0
info:供運(yùn)行期使用的一些位標(biāo)識(shí)。
instance_size:該類的實(shí)例變量大小
ivars:成員變量的數(shù)組

每一個(gè)對(duì)象本質(zhì)上都是一個(gè)類的實(shí)例。其中類定義了成員變量和成員方法的列表。對(duì)象通過對(duì)象的isa指針指向類。
每一個(gè)類本質(zhì)上都是一個(gè)對(duì)象,類其實(shí)是元類(meteClass)的實(shí)例。元類定義了類方法的列表。類通過類的isa指針指向元類。
所有的元類最終繼承一個(gè)根元類,根元類isa指針指向本身,形成一個(gè)封閉的內(nèi)循環(huán)。

17.RunLoop有幾種事件源?有幾種模式?

輸入事件來源

Run loop接收輸入事件來自兩種不同的來源:輸入源(input source)和定時(shí)源(timer source)。兩種源都使用程序的某一特定的處理例程來處理到達(dá)的事件。
當(dāng)你創(chuàng)建輸入源,你需要將其分配給run loop中的一個(gè)或多個(gè)模式(什么是模式,下文將會(huì)講到)。模式只會(huì)在特定事件影響監(jiān)聽的源。大多數(shù)情況下,run loop運(yùn)行在默認(rèn)模式下,但是你也可以使其運(yùn)行在自定義模式。若某一源在當(dāng)前模式下不被監(jiān)聽,那么任何其生成的消息只在run loop運(yùn)行在其關(guān)聯(lián)的模式下才會(huì)被傳遞。

輸入源(input source)
傳遞異步事件,通常消息來自于其他線程或程序。輸入源傳遞異步消息給相應(yīng)的處理例程,并調(diào)用runUntilDate:方法來退出(在線程里面相關(guān)的NSRunLoop對(duì)象調(diào)用)

基于端口的輸入源
基于端口的輸入源由內(nèi)核自動(dòng)發(fā)送。
Cocoa和Core Foundation內(nèi)置支持使用端口相關(guān)的對(duì)象和函數(shù)來創(chuàng)建的基于端口的源。例如,在Cocoa里面你從來不需要直接創(chuàng)建輸入源。你只要簡(jiǎn)單的創(chuàng)建端口對(duì)象,并使用NSPort的方法把該端口添加到run loop。端口對(duì)象會(huì)自己處理創(chuàng)建和配置輸入源。
在Core Foundation,你必須人工創(chuàng)建端口和它的run loop源。我們可以使用端口相關(guān)的函數(shù)(CFMachPortRef,CFMessagePortRef,CFSocketRef)來創(chuàng)建合適的對(duì)象。下面的例子展示了如何創(chuàng)建一個(gè)基于端口的輸入源,將其添加到run loop并啟動(dòng):

voidcreatePortSource()
{
    CFMessagePortRef port = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("com.someport"),myCallbackFunc, NULL, NULL);

    CFRunLoopSourceRef source =  CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
    while (pageStillLoading) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        CFRunLoopRun();
        [pool release];
    }
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}

自定義輸入源
自定義的輸入源需要人工從其他線程發(fā)送。
為了創(chuàng)建自定義輸入源,必須使用Core Foundation里面的CFRunLoopSourceRef類型相關(guān)的函數(shù)來創(chuàng)建。你可以使用回調(diào)函數(shù)來配置自定義輸入源。Core Fundation會(huì)在配置源的不同地方調(diào)用回調(diào)函數(shù),處理輸入事件,在源從run loop移除的時(shí)候清理它。
除了定義在事件到達(dá)時(shí)自定義輸入源的行為,你也必須定義消息傳遞機(jī)制。源的這部分運(yùn)行在單獨(dú)的線程里面,并負(fù)責(zé)在數(shù)據(jù)等待處理的時(shí)候傳遞數(shù)據(jù)給源并通知它處理數(shù)據(jù)。消息傳遞機(jī)制的定義取決于你,但最好不要過于復(fù)雜。創(chuàng)建并啟動(dòng)自定義輸入源的示例如下:

voidcreateCustomSource()
{
    CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};

    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);

    while (pageStillLoading) {

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        CFRunLoopRun();
        [pool release];
    }
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}

Cocoa上的Selector源
除了基于端口的源,Cocoa定義了自定義輸入源,允許你在任何線程執(zhí)行selector方法。和基于端口的源一樣,執(zhí)行selector請(qǐng)求會(huì)在目標(biāo)線程上序列化,減緩許多在線程上允許多個(gè)方法容易引起的同步問題。不像基于端口的源,一個(gè)selector執(zhí)行完后會(huì)自動(dòng)從run loop里面移除。
當(dāng)在其他線程上面執(zhí)行selector時(shí),目標(biāo)線程須有一個(gè)活動(dòng)的run loop。對(duì)于你創(chuàng)建的線程,這意味著線程在你顯式的啟動(dòng)run loop之前是不會(huì)執(zhí)行selector方法的,而是一直處于休眠狀態(tài)。
NSObject類提供了類似如下的selector方法:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)argwaitUntilDone:(BOOL)wait modes:(NSArray *)array;

定時(shí)源(timer source)
定時(shí)源在預(yù)設(shè)的時(shí)間點(diǎn)同步方式傳遞消息,這些消息都會(huì)發(fā)生在特定時(shí)間或者重復(fù)的時(shí)間間隔。定時(shí)源則直接傳遞消息給處理例程,不會(huì)立即退出run loop。
需要注意的是,盡管定時(shí)器可以產(chǎn)生基于時(shí)間的通知,但它并不是實(shí)時(shí)機(jī)制。和輸入源一樣,定時(shí)器也和你的run loop的特定模式相關(guān)。如果定時(shí)器所在的模式當(dāng)前未被run loop監(jiān)視,那么定時(shí)器將不會(huì)開始直到run loop運(yùn)行在相應(yīng)的模式下。類似的,如果定時(shí)器在run loop處理某一事件期間開始,定時(shí)器會(huì)一直等待直到下次run loop開始相應(yīng)的處理程序。如果run loop不再運(yùn)行,那定時(shí)器也將永遠(yuǎn)不啟動(dòng)。
創(chuàng)建定時(shí)器源有兩種方法:

方法一:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4.0
                                                     target:self                                        selector:@selector(backgroundThreadFire:) userInfo:nil

                                                    repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timerforMode:NSDefaultRunLoopMode];

方法二:
[NSTimer scheduledTimerWithTimeInterval:10
                                        target:self

                                   selector:@selector(backgroundThreadFire:)

                                       userInfo:nil

                                       repeats:YES];

Cocoa中的預(yù)定義模式有:

  • Default模式
    定義:NSDefaultRunLoopMode (Cocoa) kCFRunLoopDefaultMode (Core Foundation)
    描述:默認(rèn)模式中幾乎包含了所有輸入源(NSConnection除外),一般情況下應(yīng)使用此模式。
  • Connection模式
    定義:NSConnectionReplyMode(Cocoa)
    描述:處理NSConnection對(duì)象相關(guān)事件,系統(tǒng)內(nèi)部使用,用戶基本不會(huì)使用。
  • Modal模式
    定義:NSModalPanelRunLoopMode(Cocoa)
    描述:處理modal panels事件。
  • Event tracking模式
    定義:UITrackingRunLoopMode(iOS) NSEventTrackingRunLoopMode(cocoa)
    描述:在拖動(dòng)loop或其他user interface tracking loops時(shí)處于此種模式下,在此模式下會(huì)限制輸入事件的處理。例如,當(dāng)手指按住UITableView拖動(dòng)時(shí)就會(huì)處于此模式。
  • Common模式
    定義:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)
    描述:這是一個(gè)偽模式,其為一組run loop mode的集合,將輸入源加入此模式意味著在Common Modes中包含的所有模式下都可以處理。在Cocoa應(yīng)用程序中,默認(rèn)情況下Common Modes包含default modes,modal modes,event Tracking modes.可使用CFRunLoopAddCommonMode方法想Common Modes中添加自定義modes。

Run loop的優(yōu)點(diǎn):
首先,NSRunLoop是一種更加高明的消息處理模式,他就高明在對(duì)消息處理過程進(jìn)行了更好的抽象和封裝,這樣才能是的你不用處理一些很瑣碎很低層次的具體消息的處理,在NSRunLoop中每一個(gè)消息就被打包在input source或者是timer source(見后文)中了。
其次,也是很重要的一點(diǎn),使用run loop可以使你的線程在有工作的時(shí)候工作,沒有工作的時(shí)候休眠,這可以大大節(jié)省系統(tǒng)資源。

18.lldb(gdb)常用的調(diào)試命令?

po:打印對(duì)象,會(huì)調(diào)用對(duì)象description方法。是print-object的簡(jiǎn)寫
expr:可以在調(diào)試時(shí)動(dòng)態(tài)執(zhí)行指定表達(dá)式,并將結(jié)果打印出來,很有用的命令
print:也是打印命令,需要指定類型
bt:打印調(diào)用堆棧,是thread backtrace的簡(jiǎn)寫,加all可打印所有thread的堆棧
br l:是breakpoint list的簡(jiǎn)寫

19.performSelector延時(shí)調(diào)用導(dǎo)致的內(nèi)存泄露

最后的最后才發(fā)現(xiàn)實(shí)際上是performSelector延時(shí)調(diào)用的問題,經(jīng)查找資料,performSelector關(guān)于內(nèi)存管理的執(zhí)行原理是這樣的執(zhí)行 [self performSelector:@selector(method1:) withObject:self.tableLayer afterDelay:3]; 的時(shí)候,系統(tǒng)會(huì)將tableLayer的引用計(jì)數(shù)加1,執(zhí)行完這個(gè)方法時(shí),還會(huì)將tableLayer的引用計(jì)數(shù)減1,而在我的游戲里這個(gè)延時(shí)執(zhí)行函數(shù)是被多次調(diào)用的,有時(shí)切換場(chǎng)景時(shí)延時(shí)函數(shù)已經(jīng)被調(diào)用但還沒有執(zhí)行,這時(shí)tableLayer的引用計(jì)數(shù)沒有減少到0,也就導(dǎo)致了切換場(chǎng)景dealloc方法沒有被調(diào)用,出現(xiàn)了內(nèi)存泄露。

所以最后我的解決辦法就是取消那些還沒有來得及執(zhí)行的延時(shí)函數(shù),代碼很簡(jiǎn)單:
[NSObject cancelPreviousPerformRequestsWithTarget:self]
當(dāng)然你也可以一個(gè)一個(gè)得這樣用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]

加上了這個(gè)以后,切換場(chǎng)景也就很順利地執(zhí)行了dealloc方法,至此問題解決!
最后在找資料時(shí)也發(fā)現(xiàn)了,延時(shí)調(diào)用實(shí)現(xiàn)長(zhǎng)按鈕的實(shí)現(xiàn)思路,記錄下來以備后用:
在touchBegan里面

[self performSelector:@selector(longPressMethod:) withObject:nil afterDelay:longPressTime]

然后在end 或cancel里做判斷,如果時(shí)間不夠長(zhǎng)按的時(shí)間調(diào)用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPressMethod:) object:nil]

取消began里的方法

最后最后總結(jié):
performSelector是一個(gè)很有用的函數(shù),跟它打過不少交道,經(jīng)過血與淚的教訓(xùn),總結(jié)一下它的使用如下:
使用前先檢測(cè)一下,

SEL testSelector = @selector(test:);   
 if([tester respondsToSelector:testSelector])  
  {  
          //如果響應(yīng)就執(zhí)行
          [tester test:@"invoke test method"];  
  }

使用后,如果有必要,需要顯示的調(diào)用cancelPreviousPerformRequestsWithTarget:selector:object: ,否則有可能產(chǎn)生內(nèi)存泄露,而且這種內(nèi)存泄露很難發(fā)現(xiàn),因?yàn)樗⒉贿`反任何規(guī)則,所以一定要注意!

20.如何對(duì)真機(jī)的crash日志進(jìn)行分析?

獲取真機(jī)crash日志

連接真機(jī)
找到Xcode --> Window --> Devices
獲取所有的crash日志文件
右鍵可以Export,就可以查看相關(guān)的crash的原因

分析crash日志

有如下3種方法

方法1 使用XCode
這種方法可能是最容易的方法了。
需要使用Xcode符號(hào)化 crash log,你需要下面所列的3個(gè)文件:

  1. crash報(bào)告(.crash文件)
  2. 符號(hào)文件 (.dsymb文件)
  3. 應(yīng)用程序文件 (appName.app文件,把IPA文件后綴改為zip,然后解壓,Payload目錄下的appName.app文件), 這里的appName是你的應(yīng)用程序的名稱。
    把這3個(gè)文件放到同一個(gè)目錄下,打開Xcode的Window菜單下的organizer,然后點(diǎn)擊Devices tab,然后選中左邊的Device Logs。
    然后把.crash文件拖到Device Logs或者選擇下面的import導(dǎo)入.crash文件。
    這樣你就可以看到crash的詳細(xì)log了。

方法2 使用命令行工具symbolicatecrash
有時(shí)候Xcode不能夠很好的符號(hào)化crash文件。我們這里介紹如何通過symbolicatecrash來手動(dòng)符號(hào)化crash log。
在處理之前,請(qǐng)依然將“.app“, “.dSYM”和 ".crash"文件放到同一個(gè)目錄下?,F(xiàn)在打開終端(Terminal)然后輸入如下的命令:
exportDEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
然后輸入命令:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrashappName.crashappName.app>appName.log
現(xiàn)在,符號(hào)化的crash log就保存在appName.log中了。

方法3 使用命令行工具atos
如果你有多個(gè)“.ipa”文件,多個(gè)".dSYMB"文件,你并不太確定到底“dSYMB”文件對(duì)應(yīng)哪個(gè)".ipa"文件,那么,這個(gè)方法就非常適合你。

特別當(dāng)你的應(yīng)用發(fā)布到多個(gè)渠道的時(shí)候,你需要對(duì)不同渠道的crash文件,寫一個(gè)自動(dòng)化的分析腳本的時(shí)候,這個(gè)方法就極其有用。
這里先介紹一個(gè)概念:UUID
什么是UUID
每一個(gè)可執(zhí)行程序都有一個(gè)build UUID來唯一標(biāo)識(shí)。Crash日志包含發(fā)生crash的這個(gè)應(yīng)用(app)的 build UUID以及crash發(fā)生的時(shí)候,應(yīng)用加載的所有庫文件的[build UUID]。

那如何知道crash文件的UUID呢?
可以用:
grep"appNamearmv"crash
或者
grep--after-context=2"BinaryImages:"
crash
可以得到類似如下的結(jié)果:
appName.crash-0x4000-0x9e7fffappNamearmv7<8bdeaf1a0b233ac199728c2a0ebb4165>/var/mobile/Applications/A0F8AB29-35D1-4E6E-84E2-954DE7D21CA1/appName.crash.app/appName
(請(qǐng)注意這里的0x4000,是模塊的加載地址,后面用atos的時(shí)候會(huì)用到)
如何找到app的UUID
可以使用命令:
xcrundwarfdump-–uuid
比如:
xcrundwarfdump--uuidappName.app/appName
結(jié)果如下:
UUID:8BDEAF1A-0B23-3AC1-9972-8C2A0EBB4165(armv7)appName.app/appNameUUID:5EA16BAC-BB52-3519-B218-342455A52E11(armv7s)appName.app/appName
這個(gè)app有2個(gè)UUID,表明它是一個(gè)fat binnary。
它能利用最新硬件的特性,又能兼容老版本的設(shè)備。
對(duì)比上面crash文件和app文件的UUID,發(fā)現(xiàn)它們是匹配的:
8BDEAF1A-0B23-3AC1-9972-8C2A0EBB4165
用atos命令來符號(hào)化某個(gè)特定模塊加載地址
命令是:
atos[-oAppName.app/AppName][-lloadAddress][-archarchitecture]
親測(cè),下面3種都可以:
xcrunatos-oappName.app.dSYM/Contents/Resources/DWARF/appName-l0x4000-archarmv7xcrunatos-oappName.app.dSYM/Contents/Resources/DWARF/appName-archarmv7
xcrunatos-oappName.app/appName-archarmv7
(注:這3行選任意一行執(zhí)行都可以達(dá)到目的,其中0x4000是模塊的加載地址,從上面的章節(jié)可以找到如何得到這個(gè)地址。)
文章開頭提到crash文件中有如下兩行,
3appName0x000f462a0x4000+9846184appName0x00352aee0x4000+3468014
在執(zhí)行了上面的:
xcrunatos-oappName.app.dSYM/Contents/Resources/DWARF/appName-l0x4000-archarmv7
之后,輸入如下地址:
0x00352aee

(crash文件中的第4行:4 appName 0x00352aee 0x4000 + 3468014)
可以得到結(jié)果:
-UIScrollView(UITouch)touchesEnded:withEvent:(UIScrollView+UITouch.h:26)
這樣就找到了應(yīng)用種到底是哪個(gè)模塊導(dǎo)致的crash問題。

21.對(duì)象回收時(shí)Weak指針自動(dòng)被置為nil的實(shí)現(xiàn)原理

Runtime維護(hù)著一個(gè)Weak表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有Weak指針;
Weak表是Hash表,Key是所指對(duì)象的地址,Value是Weak指針地址的數(shù)組;
在對(duì)象被回收的時(shí)候,經(jīng)過層層調(diào)用,會(huì)最終觸發(fā)下面的方法將所有Weak指針的值設(shè)為nil。

runtime源碼,objc-weak.m 的 arr_clear_deallocating 函數(shù)。
Weak指針如何注冊(cè)到Weak表中、如何維護(hù)hash表可以參考o(jì)bjc-weak.m中的其它源碼。
從實(shí)現(xiàn)中可以看出,Weak指針的使用涉及到Hash表的增刪改查,有一定的性能開銷。

Weak指針的實(shí)際應(yīng)用:
iOS 8 特有iOS相關(guān)的漏洞
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
iOS 8 的UIScrollView的delegate屬性

簡(jiǎn)單來說,方法首先根據(jù)對(duì)象地址獲取所以Weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從Weak表中刪除。

22.遠(yuǎn)程推送

當(dāng)app不在前臺(tái)時(shí),app可能將無法接收到服務(wù)器的消息,這時(shí)蘋果通過自己的服務(wù)器來和iOS設(shè)備來通信,將最新消息傳遞到iOS設(shè)備,然后iOS系統(tǒng)將指定消息投遞給對(duì)應(yīng)的app。

iOS推送通知的基本原理:
蘋果的推送服務(wù)通知是由自己專門的推送服務(wù)器APNs (Apple Push Notification service)來完成的,其過程是 APNs 接收到我們自己的應(yīng)用服務(wù)器發(fā)出的被推送的消息,將這條消息推送到指定的 iOS 的設(shè)備上,然后再由 iOS設(shè)備通知到我們的應(yīng)用程序,我們將會(huì)以通知或者聲音的形式收到推送回來的消息。 iOS 遠(yuǎn)程推送的前提是,裝有我們應(yīng)用程序的 iOS 設(shè)備,需要向 APNs 服務(wù)器注冊(cè),注冊(cè)成功后,APNs 服務(wù)器將會(huì)給我們返回一個(gè) devicetoken,我們獲取到這個(gè) token 后會(huì)將這個(gè) token 發(fā)送給我們自己的應(yīng)用服務(wù)器。當(dāng)我們需要推送消息時(shí),我們的應(yīng)用服務(wù)器將消息按照指定的格式進(jìn)行打包,然后結(jié)合 iOS 設(shè)備的 devicetoken 一起發(fā)給 APNs 服務(wù)器。我們的應(yīng)用會(huì)和 APNs 服務(wù)器維持一個(gè)基于 TCP 的長(zhǎng)連接,APNs 服務(wù)器將新消息推送到iOS 設(shè)備上,然后在設(shè)備屏幕上顯示出推送的消息。

流程中包含四次交互--四次握手:
iOS設(shè)備在剛激活時(shí)將首先向APNs服務(wù)器打招呼--請(qǐng)求tls連接,也就是說建立一個(gè)基于tls協(xié)議的長(zhǎng)連接(這種連接可以在保證雙發(fā)的身份可信的情況下,對(duì)連接后續(xù)的通信過程進(jìn)行加密,保證通信信息的安全保密性。)
APNs服務(wù)器收到請(qǐng)求后,將反饋給iOS設(shè)備一個(gè)APNs服務(wù)器的證書;
iOS設(shè)備收到證書后驗(yàn)證通過,將反饋給APNs服務(wù)器自己的證書和私鑰,二者都是設(shè)備激活過程中獲得并存在設(shè)備的鑰匙串中的(并非apple開發(fā)者網(wǎng)站上建立的證書)。
APNs服務(wù)器接收到后,通過發(fā)來的證書和私鑰驗(yàn)證連接可靠,握手成功。

針對(duì)第三個(gè)步驟:app發(fā)送device token給自己的服務(wù)器
這一步是需要開發(fā)者自己來保證安全的一步,一般我們可以模擬蘋果的機(jī)制,對(duì)device token進(jìn)行對(duì)稱加密,或者與服務(wù)器協(xié)商好撒鹽和md5的方式,保證通信過程中即使被截獲也無法被破解。當(dāng)然為了提高安全級(jí)別,可以加入認(rèn)證授權(quán)的操作,甚至模仿蘋果的tls方式來進(jìn)一步保證安全性。

針對(duì)第四個(gè)步驟:provider發(fā)送消息給APNs服務(wù)器
這一步安全性通常有兩種方式來保證:
第一種是經(jīng)典的做法,也是與設(shè)備和APNs服務(wù)器相同的做法,即通過建立tls長(zhǎng)連接來校驗(yàn)身份,四次握手后開始發(fā)送消息。與第一步差別在于第三次握手時(shí)傳給APNs服務(wù)器的apple開發(fā)者網(wǎng)站注冊(cè)的推送證書和私鑰。這樣APNs服務(wù)器可以通過證書判斷當(dāng)前通過信的對(duì)方是可信的服務(wù)器,連接建立成功,provider便可以給PNs服務(wù)器發(fā)送推送消息,要求其轉(zhuǎn)發(fā)。

針對(duì)第五個(gè)步驟:APNs服務(wù)器推送消息到設(shè)備
這一步的安全性其實(shí)是基于上面注冊(cè)推送服務(wù)時(shí)已經(jīng)建立好的基于tls協(xié)議的長(zhǎng)連接,這時(shí)APNs服務(wù)器根據(jù)provider的請(qǐng)求中device token使用秘鑰解碼得到設(shè)備的id和app的bundle id, 這樣通過設(shè)備的id 判斷這個(gè)設(shè)備在線并且可以信任,直接將推送消息發(fā)給設(shè)備上的對(duì)應(yīng)的app,app中可以通過api來獲取到最新一條推送的內(nèi)容:
didReceiveRemoteNotification 或 applicationdidFinishLaunchingWithOptions
第二個(gè)接口對(duì)應(yīng)app已經(jīng)掛起后用戶點(diǎn)擊推送的消息彈窗后的響應(yīng)。

但是設(shè)備如果不在線呢?
關(guān)于這種情況,官方說法是有一種QoS保障: 當(dāng)設(shè)備不在線時(shí),如果收到很多條推送,只保留最后一條推送一定時(shí)間,如果超時(shí)則舍棄。

推送的過程經(jīng)過如下步驟:
1.首先,我們的設(shè)備安裝了具有推送功能的應(yīng)用(應(yīng)用程序要用代碼注冊(cè)消息推動(dòng)),我們的 iOS設(shè)備在有網(wǎng)絡(luò)的情況下會(huì)連接APNs推送服務(wù)器,連接過程中,APNS 服務(wù)器會(huì)驗(yàn)證devicetoken,連接成功后維持一個(gè)基于TCP 的長(zhǎng)連接;
2.Provider(我們自己的應(yīng)用服務(wù)器)收到需要被推送的消息并結(jié)合被推送的 iOS設(shè)備的devicetoken一起打包發(fā)送給APNS服務(wù)器;
3.APNS服務(wù)器將推送信息推送給指定devicetoken的iOS設(shè)備;
4.iOS設(shè)備收到推送消息后通知我們的應(yīng)用程序并顯示和提示用戶(聲音、彈出框)

23.熱修復(fù)

4種熱修復(fù)方式

1.Dynamic Framework
區(qū)別于靜態(tài)庫的編譯時(shí)鏈接,動(dòng)態(tài)庫是在程序運(yùn)行時(shí)動(dòng)態(tài)加載的,并且可以多個(gè)程序共享,動(dòng)態(tài)庫中包含修復(fù)的的代碼即可實(shí)現(xiàn)熱修復(fù)。
這種技術(shù)問題在于雖然apple從xcode6開放了用戶自己建立動(dòng)態(tài)framework的權(quán)利(參考iOS中的SDK開發(fā)),但是為了保證系統(tǒng)安全性(可能多個(gè)程序公用同一個(gè)動(dòng)態(tài)庫,存在兼容性問題),apple只允許系統(tǒng)自己的動(dòng)態(tài)庫出現(xiàn),而用戶自己開發(fā)的這種動(dòng)態(tài)庫只能用于企業(yè)分發(fā)的app,無法用在上架appstore的app中。

2.CodePush
CodePush是微軟推出的一種熱修復(fù)技術(shù),但主要用戶對(duì)app中ReactNative(ReactNative是facebook提供的一種開源框架,能夠用JavaScript腳本就可以寫出App的界面,使用JS語法進(jìn)行跨平臺(tái)開發(fā))部分的熱修復(fù)

3.Lua+wax
Wax 阿里開發(fā),lua腳本,支持arm64,普及少
2013年之前wax雖然有調(diào)試麻煩、線程不安全等問題,但已經(jīng)是當(dāng)時(shí)不錯(cuò)的熱修復(fù)方案,但是12年推出的64位的iphone5s,讓一直以來只支持32位的wax陷入尷尬,Lua字節(jié)碼也有32位與64位編譯區(qū)分,所以原來的Wax中的stdlib庫在64位無法運(yùn)行,阿里從13年接手了長(zhǎng)期無人維護(hù)的wax,修改了原有的Lua字節(jié)碼打包邏輯使其能在64位正常運(yùn)行。另外,阿里完善了block調(diào)用、lua調(diào)試等方面,讓wax方案更加易用。
Lua是一個(gè)在大量的游戲中使用的簡(jiǎn)潔、輕量、可擴(kuò)展的腳本語言,用于實(shí)現(xiàn)游戲的可配置和可更新。但Lua需要預(yù)先綁定很多C函數(shù)才可在腳本中使用,所以單獨(dú)使用Lua無法做到高復(fù)用性。Wax的核心邏輯是替換函數(shù),并且連接了Lua與Objective-C runtime,使得Lua可以調(diào)用和替換任意類的方法,甚至新增類、方法。這樣一來就能在app不發(fā)布新版的情況下,通過遠(yuǎn)程下載腳本的方式修復(fù)線上app里的bug、甚至新增一些功能。
使用時(shí),工程需要集成Lua解釋器和Wax框架。

4.JSPatch
與Lua+wax方案的想法相同,微信團(tuán)隊(duì)(bang)利用Objective-C Runtime的特性及iOS7系統(tǒng)開始支持的JavaScript腳本運(yùn)行,開發(fā)了自己的JavaScript熱修復(fù)方案--JSPatch。
JSPatch中JavaScript腳本運(yùn)行的基礎(chǔ)是JavaScriptCore,JavaScriptCore是一種JavaScript引擎,主要為webkit提供腳本處理能力,可以將JavaScript的能力更輕便地、高性能地帶給原生的iOS應(yīng)用,可以實(shí)現(xiàn)oc和JavaScript兩種語言的互轉(zhuǎn)。
JSPatch能做到通過JS調(diào)用和改寫OC方法:通過類名和方法名反射得到相應(yīng)的類和方法,也可以替換某個(gè)類的方法為新的實(shí)現(xiàn),或新注冊(cè)一個(gè)類,為類添加方法。JSPatch 的原理就是:JS傳遞字符串給OC,OC通過 Runtime 接口調(diào)用和替換OC方法。實(shí)際使用時(shí),我們一般通過下發(fā)js腳本,在app啟動(dòng)時(shí)判斷是否需要執(zhí)行腳本,如果有故障需要修復(fù),就執(zhí)行指定的js腳本。如果我們自己實(shí)現(xiàn)js腳本的下發(fā),需要自己開發(fā)平臺(tái)接口,保證腳本傳輸?shù)陌踩院透卟l(fā)能力。JSPatch善解人意的提供了這樣的JSPatch平臺(tái),并且開發(fā)了OC轉(zhuǎn)JS工具,便于將待修復(fù)的OC代碼轉(zhuǎn)為熱修復(fù)的JS代碼。

熱修復(fù)需要注意:
蘋果未來將禁用APP內(nèi)部的“動(dòng)態(tài)分發(fā)”功能,蘋果禁的JSPatch / wax/ rollout熱修復(fù)框架
要有及時(shí)的線上產(chǎn)品故障報(bào)警,包含crash的報(bào)警和核心業(yè)務(wù)出錯(cuò)的報(bào)警,開發(fā)及時(shí)定位到問題;
對(duì)于已經(jīng)通過熱修復(fù)解決的問題,下個(gè)版本要替換為新的native代碼;
不要使用熱修復(fù)添加業(yè)務(wù)模塊或大量非修復(fù)性的邏輯代碼,將給維護(hù)帶來很大麻煩;
熱修復(fù)對(duì)應(yīng)的補(bǔ)丁要充分考慮相關(guān)業(yè)務(wù)影響,測(cè)試充分,避免熱修復(fù)帶來新問題;

24.組件化開發(fā)

組件化開發(fā),就是將一個(gè)臃腫,復(fù)雜的單一工程的項(xiàng)目, 根據(jù)功能或者屬性進(jìn)行分解,拆分成為各個(gè)獨(dú)立的功能模塊或者組件 ; 然后根據(jù)項(xiàng)目和業(yè)務(wù)的需求,按照某種方式, 任意組織成一個(gè)擁有完整業(yè)務(wù)邏輯的工程。這就是所謂的組件化開發(fā)。

組件化開發(fā)的優(yōu)點(diǎn)
既然針對(duì)上述問題提到了組件化開發(fā),那就要必要交代一下組件化模塊化開發(fā)的好處。這樣在進(jìn)行對(duì)比的時(shí)候,可以更加清楚的定位我們想要解決的問題。開判斷組件化開發(fā)是不是我們需要的團(tuán)隊(duì)開發(fā)模式。
1、組件之間相互獨(dú)立。各組件開發(fā)成員之間的代碼想相互獨(dú)立編寫的,獨(dú)立編譯,獨(dú)立運(yùn)行和獨(dú)立測(cè)試的。
2、資源的重復(fù)里用,尤其是功能性,工具性的代碼,可以很輕松的重復(fù)里用
3、迭代的效率提高。通過迭代進(jìn)行功能的增減,只需要進(jìn)行組件的拆分和組合。很方便也很高效

組件化開發(fā)需要注意的問題
新項(xiàng)目在進(jìn)行組件化拆分的時(shí)候;或者老項(xiàng)目就行組件化重構(gòu)的時(shí)候需要考慮一下幾個(gè)問題。比較對(duì)于耦合度很高的老項(xiàng)目,解耦并不是一件容易的事情。
1、 組件拆分的依據(jù),即要把哪些內(nèi)容劃分成為一個(gè)組件?
可以按照以下幾個(gè)方面進(jìn)行拆分
① 基礎(chǔ)組件
全局常量、常用宏、常用的分類、常用三方框架的隔離封裝、還有一些比較常用的小功能類
② 功能組件
圖片輪播器、圖文菜單、視頻中的彈幕、相機(jī)、錄像、二維碼、下載功能、個(gè)性定制的提示框等等,都可以封裝在一個(gè)組件中
③ 業(yè)務(wù)模塊
例如電商的購(gòu)物車,訂單管理、下單流程、個(gè)人中心
再例如視頻或者直播的會(huì)員管理、視頻播放全屏,右下角小屏幕,緩存等等
2、組件化存在方式
一直在說組件化,到底什么是組件呢。組件的存在方式又是什么呢?
組件形式: 每個(gè)組件都是以pod庫的形式存在
組件內(nèi)部:組件內(nèi)部按照自己喜歡的開發(fā)模式以文件夾的形式進(jìn)行劃分
組件測(cè)試:每個(gè)組件對(duì)單獨(dú)對(duì)應(yīng)一個(gè)demo,用來完成該組件的功能測(cè)試,這樣測(cè)試機(jī)能被解耦開
3、組件的組合方式
既然組件的存在方式是以每個(gè)pod庫的形式存在的。那么我們組合組件的方法就是通過利用CocoaPods的方式添加安裝各個(gè)組件。

25.Instruments性能檢測(cè)

Time Profiler:分析代碼的執(zhí)行時(shí)間,找出導(dǎo)致程序變慢的原因。

Zombies:檢查是否訪問了僵尸對(duì)象,但是這個(gè)工具只能從上往下檢查,不智能

Allocations:用來檢查內(nèi)存分配,寫算法的那批人也用這個(gè)來檢查

Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露

Cocoa Layout:自動(dòng)布局

Core Animation:核心動(dòng)畫
FPS:一秒鐘渲染多少幀 Frame Per Second = FPS。
Core Animation給我們提供了周期性的FPS,并且考慮到了發(fā)生在程序之外的動(dòng)畫,界面滑動(dòng)FPS可以進(jìn)行測(cè)試。一般FPS是60左右,過于低的話需要進(jìn)行優(yōu)化。

26.加密

常見加密方案
編碼方案 Base64
哈希(散列)函數(shù) MD5(消息摘要算法)
SHA1
SHA256
對(duì)稱加密算法 DES
AES
非對(duì)稱加密算法 RSA
HTTPS HTTP+SSL協(xié)議

對(duì)稱加密的特點(diǎn)
加密/解密使用相同的密鑰
加密和解密的過程是可逆的
經(jīng)典算法
DES 數(shù)據(jù)加密標(biāo)準(zhǔn)
AES 高級(jí)加密標(biāo)準(zhǔn)
提示:
加密過程是先加密,再base64編碼
解密過程是先base64解碼,再解密

非對(duì)稱加密的特點(diǎn)
使用 公鑰 加密,使用 私鑰 解密
使用 私鑰 加密,使用 公鑰 解密(私鑰簽名,公鑰驗(yàn)簽)
公鑰是公開的,私鑰保密
加密處理安全,但是性能極差
經(jīng)典算法-->RSA

RSA——非對(duì)稱加密,會(huì)產(chǎn)生公鑰和私鑰,公鑰在客戶端,私鑰在服務(wù)端。公鑰用于加密,私鑰用于解密。

AES——對(duì)稱加密,直接使用給定的秘鑰加密,使用給定的秘鑰解密。(加密解密使用相同的秘鑰)

MD5——一種單向的加密方式,只能加密,不能解密
對(duì)不同的數(shù)據(jù)加密,得到的結(jié)果是定長(zhǎng)的,MD5對(duì)不同的數(shù)據(jù)進(jìn)行加密,得到的結(jié)果都是 32 個(gè)字符長(zhǎng)度的字符串

消息認(rèn)證機(jī)制(HMAC)簡(jiǎn)單說明
原理
消息的發(fā)送者和接收者有一個(gè)共享密鑰
發(fā)送者使用共享密鑰對(duì)消息加密計(jì)算得到MAC值(消息認(rèn)證碼)
消息接收者使用共享密鑰對(duì)消息加密計(jì)算得到MAC值
比較兩個(gè)MAC值是否一致
使用
客戶端需要在發(fā)送的時(shí)候把(消息)+(消息·HMAC)一起發(fā)送給服務(wù)器
服務(wù)器接收到數(shù)據(jù)后,對(duì)拿到的消息用共享的KEY進(jìn)行HMAC,比較是否一致,如果一致則信任

Base64編碼——對(duì)字節(jié)數(shù)組轉(zhuǎn)換成字符串的一種編碼方式
特點(diǎn):可以將任意的二進(jìn)制數(shù)據(jù)進(jìn)行Base64編碼
結(jié)果:所有的數(shù)據(jù)都能被編碼為并只用65個(gè)字符(A~Z a~z 0~9 + / =)就能表示的文本文件。
注意:對(duì)文件進(jìn)行base64編碼后文件數(shù)據(jù)的變化:編碼后的數(shù)據(jù)~=編碼前數(shù)據(jù)的4/3,會(huì)大1/3左右。

27.優(yōu)化CPU消耗

1.對(duì)象創(chuàng)建
原因:對(duì)象的創(chuàng)建會(huì)分配內(nèi)存、調(diào)整屬性,甚至還有文件讀寫等操作,比較消耗 CPU 資源。那么使用輕量級(jí)的對(duì)象,可能會(huì)對(duì)性能有所優(yōu)化。比如 CALayer 比 UIView 要輕量許多,那么不需要響應(yīng)觸摸事件的對(duì)象,用 CALayer 比較合適。通過 sb 創(chuàng)建視圖對(duì)象時(shí),其資源消耗要比直接使用代碼創(chuàng)建對(duì)象要大的多。在性能敏感的界面中,sb 不是一個(gè)好的選擇。

解決方案:
(1) 盡量推遲對(duì)象創(chuàng)建的時(shí)間,并把對(duì)象的創(chuàng)建分配到多個(gè)任務(wù)中去(推薦使用懶加載)。
(2) 如果對(duì)象可以復(fù)用,而且復(fù)用的代價(jià)比釋放、創(chuàng)建新對(duì)象要小,那么這類對(duì)象要盡量放在一個(gè)緩存池中復(fù)用。

2.對(duì)象調(diào)整
原因:對(duì)象調(diào)整也是經(jīng)常消耗 CPU 資源的地方,在這里特別說明一下 CALayer,CALayer 內(nèi)部并沒有屬性,當(dāng)調(diào)用屬性方法的時(shí)候,它內(nèi)部是通過運(yùn)行時(shí)為對(duì)象臨時(shí)添加一個(gè)方法,并把對(duì)應(yīng)的值保存在內(nèi)部的一個(gè)字典當(dāng)中,同時(shí)還會(huì)通知 delegate、創(chuàng)建動(dòng)畫等,非常消耗資源。UIView 的關(guān)于顯示的相關(guān)屬性(frame/bounds/transform)等實(shí)際上都是 CALayer 的屬性映射而來的,所以對(duì) UIView 的這些屬性進(jìn)行調(diào)整的時(shí)候,消耗的資源要遠(yuǎn)大于一般的屬性。

解決方案:當(dāng)視圖層次調(diào)整的時(shí)候,消耗的資源要遠(yuǎn)大于一般的屬性,所以在優(yōu)化性能時(shí),應(yīng)該盡量避免調(diào)整視圖層次、添加和移除視圖。

3.對(duì)象銷毀
原因:對(duì)象銷毀雖然消耗資源不多,但累計(jì)起來也是不容忽視的。通常當(dāng)容器類持有大量對(duì)象時(shí),其銷毀時(shí)的資源消耗也就相當(dāng)明顯。

解決方案:對(duì)象的釋放也盡量放到后臺(tái)線程中去執(zhí)行。這里有個(gè)坑:把對(duì)象捕捉到 block 中,然后扔到后臺(tái)去隨便發(fā)個(gè)消息以避免編譯器警告,就可以讓對(duì)象在后臺(tái)銷毀了。

4.布局計(jì)算
視圖布局的計(jì)算是 App 中常見的消耗 CPU 資源的地方,如果能在后臺(tái)線程中提前計(jì)算好視圖布局,并對(duì)布局進(jìn)行緩存的話,那么這個(gè)地方就不會(huì)出現(xiàn)任務(wù)性能問題了。

不論通過何種技術(shù)對(duì)視圖進(jìn)行布局,最終都會(huì)落到 UIView.frame/bounds/center 等屬性的調(diào)整上,所以盡量提前計(jì)算調(diào)整好布局,在需要時(shí)一次性調(diào)整好對(duì)應(yīng)屬性,而不要多次、頻繁的計(jì)算和調(diào)整這些屬性。

5.Autolayout
Autolayout 是蘋果集成的技術(shù),在大部分情況下也可以很好的提高開發(fā)效率,但是 Autolayout 對(duì)復(fù)雜視圖來說常常會(huì)產(chǎn)生嚴(yán)重的性能問題。隨著視圖的增長(zhǎng), Autolayout 帶來的 CPU 消耗會(huì)呈指數(shù)級(jí)上升。如果不想手動(dòng)調(diào)整 frame 等屬性,可以使用第三方 SDK。

6.文本計(jì)算
如果一個(gè)界面中包含大量的文本,文本的寬高計(jì)算會(huì)占用很大一部分資源,并且不可避免。如果沒有特殊要求,可以參考下 UILabel 內(nèi)部的實(shí)現(xiàn)方式:[NSAttributeString boundingRectWithSize:context:]來計(jì)算文本寬高,用 [NSAttributrString drawWithRect:options:context:] 來繪制文本。盡管這兩個(gè)方法性能不錯(cuò),但是扔需要放到后臺(tái)線程以避免阻塞主線程。

如果你使用 CoreText 繪制文本,那就可以先生成 CoreText 排版對(duì)象,然后自己計(jì)算,并且 CoreText 對(duì)象還可以保留以供稍后繪制使用。

7.文本渲染
屏幕上能看到的所有文本內(nèi)容控件,包括 UIWebView,在底層都是通過 CoreText 排版,繪制為 bitmap 圖顯示的。常見的文本控件(UILabel、UITextView等),其排版和繪制都是在主線程中進(jìn)行的。當(dāng)顯示大量文本的時(shí)候,CPU 的壓力會(huì)非常大。對(duì)此解決方案只有一個(gè),那就是自定義文本控件,用 TextKit 或者最底層的 CoreText 對(duì)文本異步繪制。盡管這實(shí)現(xiàn)起來非常麻煩,但帶來的優(yōu)勢(shì)也非常大,CoreText 對(duì)象創(chuàng)建好以后,能直接獲取文本寬高等信息,避免了多次計(jì)算(調(diào)整 UILabel 時(shí)計(jì)算一遍,UILabel 繪制時(shí)內(nèi)部在計(jì)算一遍);CoreText 占用內(nèi)存較少,可以緩存下來以備多次渲染。

8.圖片的解碼
當(dāng)你用 UIImage 或者 CGImageSource 的那幾個(gè)方法去創(chuàng)建圖片的時(shí)候,圖片數(shù)據(jù)并不會(huì)立刻解碼。圖片設(shè)置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 CPU 前,CGImage 中的數(shù)據(jù)才會(huì)得到解碼,這一步是發(fā)生在主線程的,并且不可避免。如果想繞開這個(gè)機(jī)制,常見的做法就是在后臺(tái)線程先把圖片繪制到 CGBitmapContent 中,然后從 Bitmap 直接創(chuàng)建圖片。目前常見的網(wǎng)絡(luò)圖片庫都有這個(gè)功能

9.圖片的繪制
圖片的繪制通常是指那些以 CG 開頭的方法把圖像放到畫布中,然后從畫布中創(chuàng)建圖片并顯示的一個(gè)過程,最常見的地方就是 [UIView drawRect:] 里面了。由于 CoreGraphic 方法通常都是線程安全的,所以圖像的繪制可以很容易的放到后臺(tái)線程去執(zhí)行

28.單例

單例的意思就是一個(gè)特殊的類,而不是一個(gè)實(shí)例,單例是全局都可以使用的唯一的一個(gè)類
系統(tǒng)單例:
1、UIApplication(應(yīng)用程序?qū)嵗?
2、NSNotificationCenter(消息中心):
3、NSFileManager(文件管理):
4、NSUserDefaults(應(yīng)用程序設(shè)置):
5、NSURLCache(請(qǐng)求緩存):
6、NSHTTPCookieStorage(應(yīng)用程序cookies池):

1.單例模式的要點(diǎn):
  顯然單例模式的要點(diǎn)有三個(gè);一是某個(gè)類只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
2.單例模式的優(yōu)點(diǎn):
  1.安全性和唯一性:Singleton 會(huì)阻止其他對(duì)象實(shí)例化其自己的 Singleton 對(duì)象的副本,從而確保所有對(duì)象都訪問唯一實(shí)例。單例類也可以防止他人復(fù)制(copy),保留(retain)或釋放(release)實(shí)例。如果您發(fā)現(xiàn)需要,您可以創(chuàng)建自己的單例。例如,如果您有一個(gè)類為應(yīng)用程序中的其他對(duì)象提供聲音,則可以將其設(shè)為單例。
  2.靈活性:因?yàn)轭惪刂屏藢?shí)例化過程,所以類可以更加靈活修改實(shí)例化過程

創(chuàng)建步驟
1、為你的單例類聲明一個(gè)靜態(tài)的實(shí)例(聲明靜態(tài)全局變量),并且初始化它的值為nil; eg:
static TestSingleton *testSingleton = nil;
這樣,在獲取實(shí)例的方法中,只有在靜態(tài)實(shí)例為nil的時(shí)候,產(chǎn)生一個(gè)你的類的實(shí)例,這個(gè)實(shí)例通常被稱為共享的實(shí)例;
2、重寫allocWithZone方法,用于確定:不能夠使用其他的方法創(chuàng)建我們類的實(shí)例,限制用戶只能通過獲取實(shí)例的方法得到這個(gè)類的實(shí)例。所以我們?cè)赼llocWithZone方法中直接返回共享的類實(shí)例;
3、寫+(instancetype)shareSingleton的函數(shù)體
創(chuàng)建方法

一、傳統(tǒng)方法

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
if (singleton == nil){ 
singleton = [[self alloc] init]; 
} 
return singleton; 
}

二、推薦方法(GCD)

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
//給單例加一個(gè)線程鎖 
static dispatch_once_t onceToken; 
dispatch_once(&onceToken, ^{ 
singleton = [[Singleton alloc] init]; 
}); 
return singleton;

三、線程加鎖方法(不推薦使用)

+(instancetype)shareSingleton{ 
static Singleton *singleton = nil; 
@synchronized(self) { 
singleton = [[Singleton alloc] init]; 
} 
return singleton; 
}

注:“線程加鎖方法”這樣性能不是很好,因?yàn)槊看握{(diào)用+ (instancetype)sharedSingleton函數(shù)都會(huì)付出取鎖的代價(jià)
吞吞吐吐:

這樣寫的話是保證了線程安全,但通過自帶的alloc或者new來進(jìn)行實(shí)例化,還是不能保證該對(duì)象只被創(chuàng)建一次,如何避免呢?他就回答不上了,其實(shí)很簡(jiǎn)單:

.h頭文件:
@interface TestSingleton : NSObject
@property (nonatomic, copy)NSString *testStr;
+ (TestSingleton *)shareinstance;
@end
.m文件:
+ (TestSingleton *)shareinstance {
    static TestSingleton  *testSingleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
//testSingleton = [self singletonAlloc]; //后面使用該創(chuàng)建方法  
testSingleton = [self new];//[[self alloc]init];
    });
    return testSingleton;
}

//我們需要重載alloc、new方法

+ (instancetype)singletonAlloc
{
    return [super alloc];
}

+ (instancetype)alloc
{
//加斷言,使用alloc會(huì)蹦,并且reason提示
    NSAssert(NO, @"不要用alloc,要使用singletonAlloc方法創(chuàng)建");
    return nil;
}
+ (instancetype)new
{
    return [self alloc];
}

+ (TestSingleton *)shareinstance {
    static TestSingleton  *testSingleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    testSingleton = [[self singletonAlloc]init]; 
    });
    return testSingleton;
}

重載了alloc、allocWithZone和new方法,在alloc方法中加上斷言來提醒,讓用戶不能使用alloc創(chuàng)建實(shí)例。

普通類允許調(diào)用者根據(jù)需要?jiǎng)?chuàng)建盡可能多的類的實(shí)例,而對(duì)于單例類,每個(gè)進(jìn)程只能有一個(gè)類的實(shí)例,保證了單例數(shù)據(jù)的唯一性,安全性

29.Objective-C堆和棧的區(qū)別?

答: 管理方式:對(duì)于棧來講,是由編譯器自動(dòng)管理,無需我們手工控制;對(duì)于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。

申請(qǐng)大小:
棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過棧的剩余空間時(shí),將提示overflow。因 此,能從棧獲得的空間較小。

堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。

碎片問題:對(duì)于堆來講,頻繁的new/delete勢(shì)必會(huì)造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對(duì)于棧來講,則不會(huì)存在這個(gè)問題,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,他們是如此的一一對(duì)應(yīng),以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中間彈出

分配方式:堆都是動(dòng)態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動(dòng)態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的,他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實(shí)現(xiàn)。

分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對(duì)棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的。

30.關(guān)鍵字const有什么含意?修飾類呢?static的作用,用于類呢?還有extern c的作用

答:
const 意味著"只讀",下面的聲明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個(gè)的作用是一樣,a是一個(gè)常整型數(shù)。
第三個(gè)意味著a是一個(gè)指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)。
第四個(gè)意思a是一個(gè)指向整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。
最后一個(gè)意味著a是一個(gè)指向常整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不可修改的)。

結(jié)論:
關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息,實(shí)際上,聲明一個(gè)參數(shù)為常量是為了告訴了用戶這個(gè)參數(shù)的應(yīng)用目的。
如果你曾花很多時(shí)間清理其它人留下的垃圾,你就會(huì)很快學(xué)會(huì)感謝這點(diǎn)多余的信息。(當(dāng)然,懂得用const的程序員很少會(huì)留下的垃圾讓別人來清理的) 通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡(jiǎn)而言之,這樣可以減少bug的出現(xiàn)。

1).欲阻止一個(gè)變量被改變,可以使用 const 關(guān)鍵字。在定義該 const 變量時(shí),通常需要對(duì)它進(jìn)行初
始化,因?yàn)橐院缶蜎]有機(jī)會(huì)再去改變它了;
2).對(duì)指針來說,可以指定指針本身為 const,也可以指定指針?biāo)傅臄?shù)據(jù)為 const,或二者同時(shí)指
定為 const;
3).在一個(gè)函數(shù)聲明中,const 可以修飾形參,表明它是一個(gè)輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值;
4).對(duì)于類的成員函數(shù),若指定其為 const 類型,則表明其是一個(gè)常函數(shù),不能修改類的成員變量;
5).對(duì)于類的成員函數(shù),有時(shí)候必須指定其返回值為 const 類型,以使得其返回值不為“左值”。

31.關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子。

答:一個(gè)定義為 volatile的變量是說這變量可能會(huì)被意想不到地改變,這樣,編譯器就不會(huì)去假設(shè)這個(gè)變量的值了。精確地說就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份。
下面是volatile變量的幾個(gè)例子:
并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
一個(gè)中斷服務(wù)子程序中會(huì)訪問到的非自動(dòng)變量(Non-automatic variables)
多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量

32. 一個(gè)參數(shù)既可以是const還可以是volatile嗎? 一個(gè)指針可以是volatile 嗎?解釋為什么。

答:1).是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖?。它是const因?yàn)槌绦虿粦?yīng)該試圖去修改它。
2).是的。盡管這并不很常見。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer的指針時(shí)。

33.static 關(guān)鍵字的作用:

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

34.線程與進(jìn)程的區(qū)別和聯(lián)系?

答:
1). 進(jìn)程和線程都是由操作系統(tǒng)所體會(huì)的程序運(yùn)行的基本單元,系統(tǒng)利用該基本單元實(shí)現(xiàn)系統(tǒng)對(duì)應(yīng)用的并發(fā)性
2). 進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。
3). 進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。
4.)線程有自己的堆棧和局部變量,但線程之間沒有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉。所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。
5). 但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。

35.列舉幾種進(jìn)程的同步機(jī)制,并比較其優(yōu)缺點(diǎn)。

答: 原子操作 信號(hào)量機(jī)制 自旋鎖 管程,會(huì)合,分布式系統(tǒng)

36. 進(jìn)程之間通信的途徑

答:共享存儲(chǔ)系統(tǒng)消息傳遞系統(tǒng)管道:以文件系統(tǒng)為基礎(chǔ)

37. 進(jìn)程死鎖的原因

答:資源競(jìng)爭(zhēng)及進(jìn)程推進(jìn)順序非法

38. 死鎖的4個(gè)必要條件

答:互斥、請(qǐng)求保持、不可剝奪、環(huán)路

39. 死鎖的處理

答:鴕鳥策略、預(yù)防策略、避免策略、檢測(cè)與解除死鎖

40.cocoa touch框架

答:iPhone OS 應(yīng)用程序的基礎(chǔ) Cocoa Touch 框架重用了許多 Mac 系統(tǒng)的成熟模式,但是它更多地專注于觸摸的接口和優(yōu)化。

UIKit 為您提供了在 iPhone OS 上實(shí)現(xiàn)圖形,事件驅(qū)動(dòng)程序的基本工具,其建立在和 Mac OS X 中一樣的 Foundation 框架上,包括文件處理,網(wǎng)絡(luò),字符串操作等。

Cocoa Touch 具有和 iPhone 用戶接口一致的特殊設(shè)計(jì)。有了 UIKit,您可以使用 iPhone OS 上的獨(dú)特的圖形接口控件,按鈕,以及全屏視圖的功能,您還可以使用加速儀和多點(diǎn)觸摸手勢(shì)來控制您的應(yīng)用。

各色俱全的框架 除了UIKit 外,Cocoa Touch 包含了創(chuàng)建世界一流 iPhone 應(yīng)用程序需要的所有框架,從三維圖形,到專業(yè)音效,甚至提供設(shè)備訪問 API 以控制攝像頭,或通過 GPS 獲知當(dāng)前位置。

Cocoa Touch 既包含只需要幾行代碼就可以完成全部任務(wù)的強(qiáng)大的 Objective-C 框架,也在需要時(shí)提供基礎(chǔ)的 C 語言 API 來直接訪問系統(tǒng)。這些框架包括:
Core Animation:通過 Core Animation,您就可以通過一個(gè)基于組合獨(dú)立圖層的簡(jiǎn)單的編程模型來創(chuàng)建豐富的用戶體驗(yàn)。
Core Audio:Core Audio 是播放,處理和錄制音頻的專業(yè)技術(shù),能夠輕松為您的應(yīng)用程序添加強(qiáng)大的音頻功能。
Core Data:提供了一個(gè)面向?qū)ο蟮臄?shù)據(jù)管理解決方案,它易于使用和理解,甚至可處理任何應(yīng)用或大或小的數(shù)據(jù)模型。

下面是 Cocoa Touch 中一小部分可用的框架:
音頻和視頻:Core Audio ,OpenAL ,Media Library ,AV Foundation
數(shù)據(jù)管理 :Core Data ,SQLite
圖形和動(dòng)畫 :Core Animation ,OpenGL ES ,Quartz 2D
網(wǎng)絡(luò):Bonjour ,WebKit ,BSD Sockets
用戶應(yīng)用:Address Book ,Core Location ,Map Kit ,Store Kit

41.自動(dòng)釋放池是什么,如何工作

答:當(dāng)您向一個(gè)對(duì)象發(fā)送一個(gè)autorelease消息時(shí),Cocoa就會(huì)將該對(duì)象的一個(gè)引用放入到最新的自動(dòng)釋放.它仍然是個(gè)正當(dāng)?shù)膶?duì)象,因此自動(dòng)釋放池定義的作用域內(nèi)的其它對(duì)象可以向它發(fā)送消息。當(dāng)程序執(zhí)行到作用域結(jié)束的位置時(shí),自動(dòng)釋放池就會(huì)被釋放,池中的所有對(duì)象也就被釋放。

42. Objective-C的優(yōu)缺點(diǎn)。

答:objc優(yōu)點(diǎn):
1). Cateogies
2). Posing
3). 動(dòng)態(tài)識(shí)別
4).指標(biāo)計(jì)算
5).彈性訊息傳遞
6).不是一個(gè)過度復(fù)雜的 C 衍生語言
7).Objective-C 與 C++ 可混合編程
objc缺點(diǎn):
1).不支援命名空間
2).不支持運(yùn)算符重載
3).不支持多重繼承
4).使用動(dòng)態(tài)運(yùn)行時(shí)類型,所有的方法都是函數(shù)調(diào)用,所以很多編譯時(shí)優(yōu)化方法都用不到。(如內(nèi)聯(lián)函數(shù)等),性能低劣。

43.sprintf,strcpy,memcpy使用上有什么要注意的地方。

答:
1). sprintf是格式化函數(shù)。將一段數(shù)據(jù)通過特定的格式,格式化到一個(gè)字符串緩沖區(qū)中去。sprintf格式化的函數(shù)的長(zhǎng)度不可控,有可能格式化后的字符串會(huì)超出緩沖區(qū)的大小,造成溢出。
2).strcpy是一個(gè)字符串拷貝的函數(shù),它的函數(shù)原型為strcpy(char *dst, const char *src
將src開始的一段字符串拷貝到dst開始的內(nèi)存中去,結(jié)束的標(biāo)志符號(hào)為 ‘\0',由于拷貝的長(zhǎng)度不是由我們自己控制的,所以這個(gè)字符串拷貝很容易出錯(cuò)。
3). memcpy是具備字符串拷貝功能的函數(shù),這是一個(gè)內(nèi)存拷貝函數(shù),它的函數(shù)原型為memcpy(char dst, const char src, unsigned int len);將長(zhǎng)度為len的一段內(nèi)存,從src拷貝到dst中去,這個(gè)函數(shù)的長(zhǎng)度可控。但是會(huì)有內(nèi)存疊加的問題。

44.http和scoket通信的區(qū)別。

答:HTTP超文本傳輸協(xié)議,是短連接,是客戶端主動(dòng)發(fā)送請(qǐng)求,服務(wù)器做出響應(yīng),服務(wù)器響應(yīng)之后,鏈接斷開。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)正文。
http是客戶端用http協(xié)議進(jìn)行請(qǐng)求,發(fā)送請(qǐng)求時(shí)候需要封裝http請(qǐng)求頭,并綁定請(qǐng)求的數(shù)據(jù),服務(wù)器一般有web服務(wù)器配合(當(dāng)然也非絕對(duì))。 http請(qǐng)求方式為客戶端主動(dòng)發(fā)起請(qǐng)求,服務(wù)器才能給響應(yīng),一次請(qǐng)求完畢后則斷開連接,以節(jié)省資源。服務(wù)器不能主動(dòng)給客戶端響應(yīng)(除非采取http長(zhǎng)連接 技術(shù))。iphone主要使用類是NSUrlConnection。

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

45.TCP和UDP的區(qū)別

答: TCP全稱是Transmission Control Protocol,中文名為傳輸控制協(xié)議,它可以提供可靠的、面向連接的網(wǎng)絡(luò)數(shù)據(jù)傳遞服務(wù)。傳輸控制協(xié)議主要包含下列任務(wù)和功能:

  • 確保IP數(shù)據(jù)報(bào)的成功傳遞。
  • 對(duì)程序發(fā)送的大塊數(shù)據(jù)進(jìn)行分段和重組。
  • 確保正確排序及按順序傳遞分段的數(shù)據(jù)。
  • 通過計(jì)算校驗(yàn)和,進(jìn)行傳輸數(shù)據(jù)的完整性檢查。
    TCP連接的三次握手:
    第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);
    第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包,即SYN+ACK包,此時(shí)服務(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),完成三次狀態(tài)。
    UDP為用戶數(shù)據(jù)報(bào)協(xié)議,非連接的不可靠的點(diǎn)到多點(diǎn)的通信;
    TCP提供的是面向連接的、可靠的數(shù)據(jù)流傳輸,而UDP提供的是非面向連接的、不可靠的數(shù)據(jù)流傳輸。
    簡(jiǎn)單的說,TCP注重?cái)?shù)據(jù)安全,而UDP數(shù)據(jù)傳輸快點(diǎn),但安全性一般

46.請(qǐng)簡(jiǎn)要說明viewDidLoad和viewDidUnload何時(shí)調(diào)用

答:viewDidLoad在view從nib文件初始化時(shí)調(diào)用,loadView在controller的view為nil時(shí)調(diào)用。此方法在編程實(shí)現(xiàn)view時(shí)調(diào)用,view控制器默認(rèn)會(huì)注冊(cè)memory warning notification,當(dāng)view controller的任何view沒有用的時(shí)候,viewDidUnload會(huì)被調(diào)用,在這里實(shí)現(xiàn)將retain的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會(huì)負(fù)責(zé)release 。

簡(jiǎn)述視圖控件器的生命周期。
loadView 盡管不直接調(diào)用該方法,如多手動(dòng)創(chuàng)建自己的視圖,那么應(yīng)該覆蓋這個(gè)方法并將它們賦值給試圖控制器的 view 屬性。

viewDidLoad 只有在視圖控制器將其視圖載入到內(nèi)存之后才調(diào)用該方法,這是執(zhí)行任何其他初始化操作的入口。

viewDidUnload 當(dāng)試圖控制器從內(nèi)存釋放自己的方法的時(shí)候調(diào)用,用于清楚那些可能已經(jīng)在試圖控制器中創(chuàng)建的對(duì)象。

viewVillAppear 當(dāng)試圖將要添加到窗口中并且還不可見的時(shí)候或者上層視圖移出圖層后本視圖變成頂級(jí)視圖時(shí)調(diào)用該方法,用于執(zhí)行諸如改變視圖方向等的操作。實(shí)現(xiàn)該方法時(shí)確保調(diào)用 [super viewWillAppear:

viewDidAppear 當(dāng)視圖添加到窗口中以后或者上層視圖移出圖層后本視圖變成頂級(jí)視圖時(shí)調(diào)用,用于放置那些需要在視圖顯示后執(zhí)行的代碼。確保調(diào)用 [super viewDidAppear:] 。

47. 簡(jiǎn)述內(nèi)存分區(qū)情況

答:
1).代碼區(qū):存放函數(shù)二進(jìn)制代碼
2).數(shù)據(jù)區(qū):系統(tǒng)運(yùn)行時(shí)申請(qǐng)內(nèi)存并初始化,系統(tǒng)退出時(shí)由系統(tǒng)釋放。存放全局變量、靜態(tài)變量、常量
3).堆區(qū):通過malloc等函數(shù)或new等操作符動(dòng)態(tài)申請(qǐng)得到,需程序員手動(dòng)申請(qǐng)和釋放
4).棧區(qū):函數(shù)模塊內(nèi)申請(qǐng),函數(shù)結(jié)束時(shí)由系統(tǒng)自動(dòng)釋放。存放局部變量、函數(shù)參數(shù)

48.隊(duì)列和棧有什么區(qū)別:

答:隊(duì)列和棧是兩種不同的數(shù)據(jù)容器。從”數(shù)據(jù)結(jié)構(gòu)”的角度看,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同。
隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),它在兩端進(jìn)行操作,一端進(jìn)行入隊(duì)列操作,一端進(jìn)行出列隊(duì)操作。
棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),它只能在棧頂進(jìn)行操作,入棧和出棧都在棧頂操作。

49.HTTP協(xié)議中,POST和GET的區(qū)別是什么?

答:GET請(qǐng)求:參數(shù)在地址后拼接,沒有請(qǐng)求數(shù)據(jù),不安全(因?yàn)樗袇?shù)都拼接在地址后面),不適合傳輸大量數(shù)據(jù)(長(zhǎng)度有限制,為1024個(gè)字節(jié))。
GET提交、請(qǐng)求的數(shù)據(jù)會(huì)附在URL之后,即把數(shù)據(jù)放置在HTTP協(xié)議頭<requestline>中。以?分割URL和傳輸數(shù)據(jù),多個(gè)參數(shù)用&連接。如果數(shù)據(jù)是英文字母或數(shù)字,原樣發(fā)送,
如果是空格,轉(zhuǎn)換為+,如果是中文/其他字符,則直接把字符串用BASE64加密。
POST請(qǐng)求:參數(shù)在請(qǐng)求數(shù)據(jù)區(qū)放著,相對(duì)GET請(qǐng)求更安全,并且數(shù)據(jù)大小沒有限制。把提交的數(shù)據(jù)放置在HTTP包的包體<request-body>中.
GET提交的數(shù)據(jù)會(huì)在地址欄顯示出來,而POST提交,地址欄不會(huì)改變。
傳輸數(shù)據(jù)的大小:
GET提交時(shí),傳輸數(shù)據(jù)就會(huì)受到URL長(zhǎng)度限制,POST由于不是通過URL傳值,理論上書不受限。
安全性:
POST的安全性要比GET的安全性高;
通過GET提交數(shù)據(jù),用戶名和密碼將明文出現(xiàn)在URL上,比如登陸界面有可能被瀏覽器緩存。
1).GET 方法
GET 方法提交數(shù)據(jù)不安全,數(shù)據(jù)置于請(qǐng)求行,客戶端地址欄可見;
GET 方法不可以設(shè)置書簽
2).POST 方法
POST 方法提交數(shù)據(jù)安全,數(shù)據(jù)置于消息主體內(nèi),客戶端不可見
POST 方法可以設(shè)置書簽

50.iOS的系統(tǒng)架構(gòu)

答: iOS的系統(tǒng)架構(gòu)分為( 核心操作系統(tǒng)層 theCore OS layer )、( 核心服務(wù)層theCore Services layer )、( 媒體層 theMedia layer )和( Cocoa 界面服務(wù)層 the Cocoa Touch layer )四個(gè)層次。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,194評(píng)論 8 265
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,761評(píng)論 25 709
  • 明天是母親節(jié),我的身份今天都過了一遍! 早上得知千里之外的兒子要趕回南寧,開心的勁爆棚了! 中午從杭州...
    思慕許姐閱讀 284評(píng)論 0 0
  • 昨晚回家,半路上接到老婆打來的電話說有沒有回家了?我本以為是要等我來洗眼鏡,后來老婆說你懂的,我就知道...
    藍(lán)海煮雨閱讀 602評(píng)論 7 5
  • 通過對(duì)個(gè)案咨詢課程的學(xué)習(xí),我對(duì)個(gè)案咨詢有了一些初步的理解。 首先,咨詢的意思是通過某些人頭腦中所儲(chǔ)備的知識(shí)...
    5aae4a31c9ea閱讀 1,247評(píng)論 0 0

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