? ? ? 近期在準(zhǔn)備找工作和面試的事,閑暇之余,總結(jié)我近期面試的一些常見問(wèn)題與心得公般。自己做一下筆記忍啸,也給近期需要面試的同學(xué)一些參考砰琢,文章如有不嚴(yán)謹(jǐn)、錯(cuò)誤或侵權(quán)之處良瞧,歡迎各路大牛提出并指正陪汽。
? ? ? 大致問(wèn)題應(yīng)該是這樣的:首先會(huì)問(wèn)幾個(gè)深度稍微高點(diǎn)的問(wèn)題(如響應(yīng)者鏈如何執(zhí)行的、KVO的底層實(shí)現(xiàn)原理褥蚯、core Frameworks等)挚冤,然后再轉(zhuǎn)到基礎(chǔ) 問(wèn)一些老生常談的問(wèn)題(如tableView的優(yōu)化、關(guān)于三種多線程的用法等)赞庶。
? ? ? 接下來(lái)進(jìn)入正題:
1训挡、UIViewController的超類(父類)是誰(shuí)?響應(yīng)者鏈?zhǔn)鞘裁雌缜浚渴录l(fā)生后的處理過(guò)程澜薄?
? ? ? ?答:UIViewController的父類是UIResponder(所有能接受并處理事件的對(duì)象都直接或者間接繼承了UIResponder,其中UIApplication摊册、UIViewController肤京、UIView都是直接繼承UIResponder)。
? ? ? ?響應(yīng)者鏈簡(jiǎn)單的說(shuō)茅特,就是一系列響應(yīng)者對(duì)象構(gòu)成的一條具有先后關(guān)系的鏈條忘分。
? ? ? ?事件發(fā)生之后棋枕,處理事件的過(guò)程分為事件的傳遞和事件的響應(yīng)。
? ? ? ?事件發(fā)生后首先執(zhí)行傳遞操作妒峦,事件的傳遞過(guò)程為:事件(如觸摸重斑、移動(dòng)等)發(fā)生后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中肯骇,UIApplication會(huì)從隊(duì)列中取出最前面的事件窥浪,并將事件分發(fā)出去進(jìn)行處理, 第一步通常先傳遞給主窗口UIWindow累盗,然后由主窗口在視圖層次結(jié)構(gòu)中尋找最合適的視圖來(lái)處理事件寒矿。
? ? ? ?找到合適的控件的方法為:
? ? ? ?1、首先判斷主窗口能否能夠接受事件(判斷方式為:一若债、是否直接或者間接繼承了UIResponder符相;二、是否開啟了用戶交互self.userInteractionEnabled = YES蠢琳;三啊终、是否設(shè)置了隱藏self.hidden = YES;四傲须、透明度是否小于0.01self.alpha < 0.01)蓝牲。?
? ? ? ?2、如果能接受事件泰讽、則判斷觸摸點(diǎn)是否在自己身上例衍。
? ? ? ?3、如果觸摸點(diǎn)在自己身上已卸,則主窗口從后往前遍歷自己的子控件(為了找到適合處理事件 的子view)佛玄。
? ? ? ?4、找到合適的子控件以后重復(fù)上面的3個(gè)步驟(1累澡、判斷子控件是否能夠接受事件梦抢,2、判斷觸摸點(diǎn)是否在子控件上愧哟,3奥吩、如果滿足條件1和2,則繼續(xù)遍歷子控件的子控件)蕊梧。
? ? ? ?5霞赫、如果能找到合適的子控件,就繼續(xù)遍歷望几,如果沒有合適的子控件绩脆,那么自己就成為處理事件最合適的view。
? ? ? ?判斷一個(gè)view是否為更合適的view 的方法底層實(shí)現(xiàn)是,當(dāng)事件傳遞給一個(gè)view時(shí)靴迫,該view會(huì)調(diào)用hitTest:withEvent:方法惕味,返回當(dāng)前最合適的view,該方法內(nèi)部判斷的默認(rèn)順序?yàn)椋?/p>
? ? ? ?1玉锌、判斷view能否接受事件(if(self.userInteractionEnabled ==NO||self.hidden ==YES||self.alpha <=0.01)return nil名挥。
? ? ? ?2、調(diào)用pointInside:withEvent:判斷事件是否在自己的坐標(biāo)內(nèi)主守,如果該方法返回NO禀倔,則return nil。if([selfpointInside:point withEvent:event] ==NO) return nil参淫。
? ? ? ?3救湖、從后往前遍歷子控件,找到合適的就返回子控件(判斷子控件是否合適涎才,首先要把自己坐標(biāo)上的點(diǎn)轉(zhuǎn)換成子控件坐標(biāo)上的點(diǎn)CGPoint childPoint =[self convertPoint:point toView:self.subviews[i]]鞋既,然后子控件調(diào)用hitTest:withEvent:方法,如果能處理事件且點(diǎn)在內(nèi)部耍铜,則返回當(dāng)前子控件if([self.subviews[i] hitTest:childPoint withEvent:event]) ){return [self.subviews[i]}邑闺,若找不到,就返回自己棕兼。
? ? ? ?至此為止陡舅,一個(gè)更合適的view已經(jīng)找到,說(shuō)白了事件的傳遞過(guò)程就是通過(guò)hitTest:withEvent:方法尋找到最合適的響應(yīng)鏈伴挚。
? ? ? ?因?yàn)樽詈线m的view是調(diào)用hitTest:withEvent:方法返回的view靶衍,所以在需要時(shí),我們可以重寫父控件或者當(dāng)前控件的hitTest:withEvent:方法茎芋,返回指定的view作為最適合的view摊灭。? ??
? ? ? ?接下來(lái)就是事件的響應(yīng)過(guò)程。
? ? ? ?當(dāng)找到最適合處理事件的view(first responder)時(shí)败徊,如果當(dāng)前view實(shí)現(xiàn)了touces方法,則該事件由當(dāng)前view來(lái)接受掏缎,如果方法內(nèi)部實(shí)現(xiàn)了super touches方法皱蹦,則該事件會(huì)沿著響應(yīng)鏈往上傳遞,接著上一個(gè)響應(yīng)者(next responder)就會(huì)調(diào)用touches方法處理事件眷蜈。
? ? ? ?如果當(dāng)前響應(yīng)者不實(shí)現(xiàn)touches方法沪哺,則系統(tǒng)默認(rèn)把事件向上級(jí)響應(yīng)者傳遞。
? ? ? ?以此特性可以重寫自己的touches方法和父控件的touches方法達(dá)到一個(gè)事件多個(gè)對(duì)象處理的目的酌儒。
下一個(gè)響應(yīng)者(next?responder)的指向規(guī)則為:
UIView
如果 view 是一個(gè) view controller 的 root view辜妓,nextResponder 是這個(gè) view controller.
如果 view 不是 view controller 的 root view,nextResponder 則是這個(gè) view 的 superview
UIViewController
如果 view controller 的 view 是 window 的 root view, view controller 的 nextResponder 是這個(gè) window
如果 view controller 是被其他 view controller presented調(diào)起來(lái)的,那么 view controller 的 nextResponder 就是發(fā)起調(diào)起的那個(gè) view controller
UIWindow
window 的 nextResponder 是 UIApplication 對(duì)象籍滴。
UIApplication
UIApplication 對(duì)象的 nextResponder 是 app delegate酪夷, 但是 app delegate 必須是 UIResponder 對(duì)象,并且不能使是view 孽惰,view controller 或? UIApplication 對(duì)象他本身晚岭。
以上是事件響應(yīng)的過(guò)程。
總結(jié)起來(lái)勋功,事件觸發(fā)以后處理過(guò)程分為事件的傳遞和事件的響應(yīng)兩部分坦报。
事件的傳遞由父控件向子控件傳遞(由底層向離用戶近的view傳遞):
UIApplication -> UIWindow -> UIView ->?responsive view。
事件的響應(yīng)由子控件向父控件傳遞(由離用戶最近的view向底層傳遞):
responsive view –> super view –> …..–> view controller –> window –> Application狂鞋。
2片择、什么是內(nèi)存泄漏?你見過(guò)那些內(nèi)存泄漏骚揍?用什么工具檢測(cè)內(nèi)存泄漏字管?
? ? ? ?答:內(nèi)存泄漏(Memory Leak)是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無(wú)法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi)疏咐,導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果引用自《百度百科-內(nèi)存泄漏》纤掸。
? ? ? ?iOS在ARC(自動(dòng)管理內(nèi)存)機(jī)制下導(dǎo)致內(nèi)存泄漏的根本原因是循環(huán)強(qiáng)引用,循環(huán)強(qiáng)引用的根本原因是對(duì)象的引用計(jì)數(shù)器(retainCount )無(wú)法歸零浑塞。
常見的循環(huán)強(qiáng)引用有:
1借跪、代理模式中,聲明代理屬性時(shí)酌壕,如果用strong修飾delegate掏愁,則會(huì)發(fā)生循環(huán)強(qiáng)引用的問(wèn)題,self在main函數(shù)結(jié)束之前卵牍,引用計(jì)數(shù)器為1果港,遵循代理以后,delegate又引用了一次self糊昙,此時(shí)self的retainCount == 2辛掠,當(dāng)main 函數(shù)結(jié)束以后,self引用計(jì)數(shù)器減1释牺,此時(shí)self的retainCount == 1萝衩,聲明delegate的viewControllerA仍然被self引用。viewControllerA的retainCount == 1没咙。此時(shí)viewControllerA和viewControllerB互相引用猩谊,不能釋放。所以要用weak修飾delegate避免循環(huán)強(qiáng)引用問(wèn)題祭刚。
//viewControllerA
//viewControllerB
2牌捷、ViewController中使用Block時(shí)墙牌,如果Block內(nèi)部引用了self的某些對(duì)象,因?yàn)閟elf本身已經(jīng)持有Block暗甥,所以會(huì)發(fā)生循環(huán)強(qiáng)引用喜滨。
一般情況下,Block都用于兩個(gè)類之間的相互傳值淋袖,只有一個(gè)類的話鸿市,使用Block意義就不大了。
3即碗、ViewController中的NSTimer方法焰情,如果調(diào)用之后不進(jìn)行invalidate的話,會(huì)使定時(shí)器種方法循環(huán)執(zhí)行剥懒,不能釋放内舟。
4、ViewController的子視圖初橘,如自定義cell验游,如果引用了ViewController的某個(gè)對(duì)象,可能會(huì)造成循環(huán)強(qiáng)引用保檐,所以一般在子視圖用到父視圖的對(duì)象時(shí)耕蝉,用weak或者assign修飾。
? ? ? ?檢測(cè)內(nèi)存泄漏的工具有:
1夜只、Analyze靜態(tài)分析(xcode-->product-->Analyze)
? ? ? ?靜態(tài)分析方法能發(fā)現(xiàn)大部分的問(wèn)題垒在,但是只能是靜態(tài)分析結(jié)果,有一些并不準(zhǔn)確扔亥,還有一些動(dòng)態(tài)分配內(nèi)存的情形并沒有進(jìn)行分析场躯。所以僅僅使用靜態(tài)內(nèi)存泄漏分析得到的結(jié)果并不是非常可靠旅挤,如果需要踢关,我們需要將對(duì)項(xiàng)目進(jìn)行更為完善的內(nèi)存泄漏分析和排查。那就需要用到我們下面要介紹的動(dòng)態(tài)內(nèi)存泄漏分析方法Instruments中的Leaks方法進(jìn)行排查。
2、Instrument的Leaks(檢查L(zhǎng)eaked memory內(nèi)存泄漏)或者Allocations(檢查Abandoned memory的內(nèi)存泄漏)(xcode-->product-->profile)。
從蘋果的開發(fā)者文檔里可以看到,一個(gè) app 的內(nèi)存分三類:
Leaked memory: Memory unreferenced by your application that cannot be used again or freed (also detectable by using the Leaks instrument).
Abandoned memory: Memory still referenced by your application that has no useful purpose.
Cached memory: Memory still referenced by your application that might be used again for better performance.
Leaked memory和Abandoned memory都屬于內(nèi)存泄漏(應(yīng)該釋放而沒有釋放的內(nèi)存)缔俄,在MRC下Leaked memory內(nèi)存泄露很容易出現(xiàn),因?yàn)楹苋菀淄況elease,這種內(nèi)存泄漏是已經(jīng)不被引用了(retainCount == 0了)蔬啡,但是沒有被釋放。而在ARC下诵肛,大多數(shù)內(nèi)存泄漏都是循環(huán)強(qiáng)引用造成的屹培,這種內(nèi)存泄漏稱為Abandoned memory默穴。
3、tableView的內(nèi)存/性能優(yōu)化和iOS性能優(yōu)化褪秀?
? ? ? ?答:tableView內(nèi)存優(yōu)化核心思想是:
? ? ? ?1蓄诽、cell的復(fù)用機(jī)制,在使用cell時(shí)媒吗,只會(huì)創(chuàng)建一屏幕多一個(gè)的cell仑氛,例如:如果一屏幕能裝下10個(gè)cell,系統(tǒng)只需要?jiǎng)?chuàng)建11個(gè)cell闸英,當(dāng)顯示第11個(gè)cell時(shí)锯岖,第一個(gè)cell正在失去焦點(diǎn),當(dāng)滑動(dòng)到第12個(gè)cell時(shí)甫何,第一個(gè)cell已經(jīng)完全失去焦點(diǎn)出吹,放在緩存池等待復(fù)用。此時(shí)第12個(gè)cell就會(huì)使用cellIdentifier標(biāo)識(shí)去緩存池中尋找相對(duì)應(yīng)的cell辙喂,如果存在捶牢,就不用創(chuàng)建新的cell,直接從緩存池中取出來(lái)重新賦值巍耗。這樣做的目的是為了防止cell創(chuàng)建過(guò)多浪費(fèi)內(nèi)存秋麸。
? ? ? ?2、cell滑動(dòng)時(shí)數(shù)據(jù)( 圖片)按需加載炬太,在cell數(shù)據(jù)過(guò)于龐大時(shí)灸蟆,快速滑動(dòng)很容易造成頁(yè)面卡楨,對(duì)此問(wèn)題娄琉,我首先想到的是數(shù)據(jù)的異步加載次乓,但異步加載在滑動(dòng)時(shí),操作依然會(huì)被執(zhí)行孽水,開啟線程過(guò)多時(shí)票腰,對(duì)整個(gè)app的性能也會(huì)造成很大的影響。
? ? ? ?此時(shí)可以利用父類UIScrollView的兩個(gè)代理來(lái)解決這個(gè)問(wèn)題女气。
方法一:- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate(此方法在停止拖拽時(shí)執(zhí)行)
方法二:- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView(此方法在減速停止時(shí)執(zhí)行)
? ? ? ?可利用此方法在tableView停止滑動(dòng)時(shí)杏慰,進(jìn)行圖片加載。加載前炼鞠,調(diào)用 indexPathsForVisibleRows或者visibleCells遍歷出可見部分的indexPath數(shù)組或者cell數(shù)組缘滥,然后按需加載。
? ? ? ?也可以在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中通過(guò)截取tableView的當(dāng)前狀態(tài)來(lái)進(jìn)行圖片異步加載操作谒主。
? ? ? ?具體如下圖:
最后也別忘記在內(nèi)存緊張的情況下釋放調(diào)所有的異步線程朝扼,以保證的你的app不會(huì)被系統(tǒng)強(qiáng)制關(guān)閉
- (void)didReceiveMemoryWarning{
//??釋放調(diào)異步加載圖片的線程以及所有圖片資源對(duì)象
}
還有千萬(wàn)別忘記銷毀的時(shí)候手動(dòng)把所有的使用到的代理設(shè)置nil
? ? ? ?3、提前計(jì)算并緩存好cell高度霎肯。在此給大家推薦一個(gè)由國(guó)人團(tuán)隊(duì)開發(fā)的優(yōu)化計(jì)算 UITableViewCell 高度的輕量級(jí)框架UITableView+FDTemplateLayoutCell擎颖。
? ?????4榛斯、加載多個(gè)Views的時(shí)候,盡量設(shè)置為不透明搂捧,opaque = YES驮俗,不然系統(tǒng)在顯示view時(shí),要計(jì)算多個(gè)view的疊加顏色允跑,很浪費(fèi)性能王凑。
? ? ? ?5、在添加view時(shí)聋丝,盡量在初始化的時(shí)候都添加上索烹,在使用時(shí)用hidden來(lái)控制是否顯示,避免view的動(dòng)態(tài)添加浪費(fèi)性能潮针。
?
?4术荤、全局變量、全局靜態(tài)變量每篷、局部靜態(tài)變量瓣戚?
答:先引用一下百度百科官方定義《靜態(tài)變量-引自百度百科》,
在OC中焦读,三者相同之處是三者都在堆上分配內(nèi)存子库,變量的生命周期和整個(gè)進(jìn)程相同。區(qū)別主要在于作用域的不同矗晃。
1仑嗅、全局變量:也稱為外部全局變量,該變量不僅可以在所定義的文件內(nèi)被訪問(wèn)张症,也可以在其他文件中被訪問(wèn)仓技。定義在方法外部的變量,除靜態(tài)變量之外俗他,都是外部全局變量脖捻。
2、全局(局部)靜態(tài)變量:在聲明變量時(shí)兆衅,加上static關(guān)鍵字即為靜態(tài)變量地沮。全局靜態(tài)變量和局部靜態(tài)變量的區(qū)別在于聲明的位置。定義在方法外的靜態(tài)變量稱為全局靜態(tài)變量羡亩。定義在方法內(nèi)部的靜態(tài)變量稱為局部靜態(tài)變量摩疑。全局靜態(tài)變量的作用域?yàn)楫?dāng)前文件(類),局部靜態(tài)變量的作用域?yàn)榉椒▋?nèi)部畏铆。
推薦一篇我感覺還不錯(cuò)的博文《objective-c--靜態(tài)變量雷袋,外部全局變量,常量總結(jié)》辞居。
?5片排、有使用過(guò)svn/git嗎寨腔?git常用的命令有哪些?
? ? ? ?答:都用過(guò)率寡,目前正在使用的是gitlab,工作中g(shù)it常用命令有:
? ? ? ? git clone(克隆代碼到本地)? ?git add.(代碼添加到本地臨時(shí)倉(cāng))? ?git commit -m(提交代碼到本地倉(cāng)庫(kù))? git push origin(同步代碼到遠(yuǎn)程倉(cāng)) git branch(查看當(dāng)前分支) git checkout -b(創(chuàng)建并切換到新分支) 等。
?6倚搬、什么是設(shè)計(jì)模式冶共?常用設(shè)計(jì)模式有哪些?分別描述一下每界。
? ? ? ?答:按照慣例捅僵,仍然先引用一下設(shè)計(jì)模式的百度百科官方定義《設(shè)計(jì)模式-百度百科》。
? ? ? ?簡(jiǎn)單的理解眨层,設(shè)計(jì)模式就是一種編程思想庙楚,用一套成熟解決方案去處理某一類型的具體問(wèn)題。
? ? ? ?iOS 中趴樱,常用的設(shè)計(jì)模式有如下幾種:
一馒闷、代理模式:當(dāng)一個(gè)類的某些功能需要由別的類來(lái)實(shí)現(xiàn),但是又不確定具體會(huì)是哪個(gè)類實(shí)現(xiàn)的時(shí)候叁征,會(huì)運(yùn)用到代理模式纳账,委托方制定協(xié)議方法,只要滿足條件的類都可以作為代理捺疼。
二疏虫、單例模式:單例就相當(dāng)于一個(gè)全局變量,不論在哪里需要用到這個(gè)類的實(shí)例變量,都可以通過(guò)單例方法來(lái)取得一旦創(chuàng)建了一個(gè)單例類,不論你在多少個(gè)界面中初始化調(diào)用了這個(gè)單例方法取得對(duì)象,它們所有的對(duì)象都是指向的同一塊內(nèi)存存儲(chǔ)空間、即單例類保證了該類的實(shí)例對(duì)象是唯一存在的啤呼。
三卧秘、工廠模式:當(dāng)很多不同的方法,不同的場(chǎng)景需要用到同一類型的對(duì)象時(shí)官扣,如果每次都初始化翅敌,會(huì)有很多重復(fù)或者類似的代碼,此時(shí)用到工廠方法醇锚,可以在不同場(chǎng)景直接調(diào)用該類方法哼御,減少代碼量與代碼臃腫度。
四焊唬、觀察者模式:觀察者模式是一種一對(duì)多的依賴關(guān)系恋昼,可以讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)上發(fā)生變化時(shí)赶促,會(huì)通知所有觀察者對(duì)象液肌,使它們能夠自動(dòng)更新自己。觀察者模式一般分為KVO(Key Value Observing)鸥滨、Notification兩種嗦哆。
五谤祖、MVC/MVVM模式:通過(guò)數(shù)據(jù)模型(Model),控制器邏輯(Controller)老速,視圖展示(View)將應(yīng)用程序進(jìn)行邏輯劃分粥喜。斯坦福大學(xué)iOS開發(fā)公開課中對(duì)MVC的解釋非常的形象:
Model= What your applicatioin is(not how it isdisplayed);
Controller= How your Model is presented to the users(UIlogic);
View= Your Controller’s minions.
中文理解就是:
Model就是APP的構(gòu)成成分,但并不代表它是如何展示給用戶的橘券;
Controller就是Model展示給用戶的方式额湘,代表了UI的邏輯;
View猶如Controller的小黃人旁舰,指呈現(xiàn)給用戶的界面锋华。
六、策略者模式:官方定義:The Strategy Pattern definesa family of algorithms,encapsulates each one,and makes them interchangeable.Strategy lets the algorithm vary independently from clients that use it.
個(gè)人理解:策略模式就是封裝起來(lái)的一系列算法箭窜,這些算法獨(dú)立于用戶獨(dú)立變化毯焕,不同的算法以不同的方式實(shí)現(xiàn)接口。用戶使用時(shí)不需要再使用if-else判斷執(zhí)行的算法而是直接調(diào)用不同的接口磺樱。iOS開發(fā)中常見于驗(yàn)證碼或者密碼的數(shù)字或者字母的限定纳猫。
7、KVO/KVC的底層實(shí)現(xiàn)坊罢?
? ? ? ?KVO(Key-Value Observing)续担,是一種觀察者設(shè)計(jì)模式(另一種觀察者模式是Notification),當(dāng)指定的對(duì)象的屬性被修改后活孩,則其觀察者就會(huì)接受到通知物遇。簡(jiǎn)單的說(shuō)就是每次指定的被觀察對(duì)象的屬性被修改后,KVO就會(huì)自動(dòng)通知相應(yīng)的觀察者了憾儒。
? ? ? ?KVO使用簡(jiǎn)單询兴,底層實(shí)現(xiàn)復(fù)雜,故稱之為黑魔法(isa-swizzling)起趾。具體的實(shí)現(xiàn)過(guò)程如下:
? ? ? ?當(dāng)觀察對(duì)象Person時(shí)诗舰,KVO機(jī)制動(dòng)態(tài)創(chuàng)建一個(gè)繼承自Person的名為?NSKVONotifying_Person的新類,且為NSKVONotifying_Person重寫觀察屬性的setter 方法训裆,setter 方法會(huì)負(fù)責(zé)在調(diào)用原 setter 方法之前和之后眶根,通知所有觀察對(duì)象屬性值的更改情況。
? ? ? ?在這個(gè)過(guò)程边琉,被觀察對(duì)象的 isa 指針從指向原來(lái)的Person類属百,被KVO機(jī)制修改為指向系統(tǒng)新創(chuàng)建的子類 NSKVONotifying_Person,來(lái)實(shí)現(xiàn)當(dāng)前類屬性值改變的監(jiān)聽变姨;? 從應(yīng)用層看族扰,我們完全沒有意識(shí)到有新的類出現(xiàn),這是因?yàn)橄到y(tǒng)“隱瞞”了對(duì)KVO的底層實(shí)現(xiàn)過(guò)程。但是此時(shí)如果我們創(chuàng)建一個(gè)新的名為“NSKVONotifying_Person”的類渔呵,就會(huì)發(fā)現(xiàn)系統(tǒng)運(yùn)行到注冊(cè)KVO的那段代碼時(shí)程序就崩潰怒竿,因?yàn)橄到y(tǒng)在注冊(cè)監(jiān)聽的時(shí)候動(dòng)態(tài)創(chuàng)建了名為NSKVONotifying_Person的中間類,并讓isa指針指向這個(gè)中間類了扩氢。(isa 指針的作用:每個(gè)對(duì)象都有isa 指針耕驰,指向該對(duì)象的類,它告訴 Runtime 系統(tǒng)這個(gè)對(duì)象的類是什么录豺。所以對(duì)象注冊(cè)為觀察者時(shí)耍属,isa指針指向新子類,那么這個(gè)被觀察的對(duì)象就變成新子類的對(duì)象了巩检。) 因而在該對(duì)象上對(duì) setter 的調(diào)用就會(huì)調(diào)用已重寫的 setter,從而激活鍵值通知機(jī)制示启。
? ? ? ? ? ? ? KVO為子類的觀察者屬性重寫調(diào)用存取方法的工作原理在代碼中相當(dāng)于:上述例子中兢哭,當(dāng) person.name 的值改變時(shí),Person對(duì)象的 isa 指針會(huì)指向 NSKVONotifying_Person夫嗓,意味著迟螺,在程序運(yùn)行時(shí),會(huì)動(dòng)態(tài)生成一個(gè) NSKVONotifying_Person 類舍咖,該類繼承于 Person矩父,而且該類中也有個(gè) -setName: 方法,方法中在設(shè)置 name 的同時(shí)實(shí)現(xiàn)了:
? ? ? ?KVO的鍵值觀察通知依賴于 NSObject 的兩個(gè)方法:willChangeValueForKey:和 didChangevlueForKey:排霉,在存取數(shù)值的前后分別調(diào)用2個(gè)方法:被觀察屬性發(fā)生改變之前窍株,willChangeValueForKey:被調(diào)用,通知系統(tǒng)該 keyPath 的屬性值即將變更攻柠;當(dāng)改變發(fā)生后球订, didChangeValueForKey: 被調(diào)用,通知系統(tǒng)該 keyPath 的屬性值已經(jīng)變更瑰钮;之后observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用冒滩。且重寫觀察屬性的setter 方法,這種繼承方式是在運(yùn)行時(shí)而不是編譯時(shí)實(shí)現(xiàn)的浪谴。此時(shí)已修改后的屬性值开睡,已準(zhǔn)備就緒,等待被使用苟耻。
8篇恒、iOS有幾種多線程?各有什么特點(diǎn)梁呈?
答:開啟多線程有四種方式:
1婚度、pthread ?2、NSThread ?3、GCD ?4蝗茁、NSOperationQueue
? ? ? pthread 是一套通用的多線程的 API醋虏,可以在Unix / Linux / Windows 等系統(tǒng)跨平臺(tái)使用,使用 C 語(yǔ)言編寫哮翘,需要程序員自己管理線程的生命周期颈嚼,使用難度較大,我們?cè)?iOS 開發(fā)中幾乎不使用 pthread饭寺,僅做了解阻课。以下引自《百度百科 - pthread》:
? ?????POSIX線程(POSIX threads),簡(jiǎn)稱Pthreads艰匙,是線程的POSIX標(biāo)準(zhǔn)限煞。該標(biāo)準(zhǔn)定義了創(chuàng)建和操縱線程的一整套API。在類Unix操作系統(tǒng)(Unix员凝、Linux署驻、Mac OS X等)中,都使用Pthreads作為操作系統(tǒng)的線程健霹。
其中iOS有三種多線程方式:
? ? ? ?1旺上、NSThread
? ? ? ?NSThread創(chuàng)建線程的方式有兩種:
? ? ? ?NSThread*thread = [[NSThread alloc] ?initWithTarget:self selector:@selector(test:) object:nil];
? ? ? ?[NSThread detachNewThreadSelector:@selector(test:) toTarget:self withObject:nil];
? ? ? ?2、GCD
? ????????????GCD示例鏈接
? ? ? ?3糖埋、NSOperationQueue
? ????????????NSOperation示例鏈接
9宣吱、iOS常用的加鎖方式?各有什么特點(diǎn)瞳别?
加鎖的目的通常是為了線程同步征候,避免多個(gè)線程同時(shí)訪問(wèn)某一塊內(nèi)存造成數(shù)據(jù)的不安全,某個(gè)線程加了鎖之后洒试,操作完再把鎖釋放倍奢,期間要是有其他線程想去訪問(wèn)被加鎖的變量就需要先拿到鎖,而鎖沒有釋放的話垒棋,就只有等待卒煞,直到擁有鎖的線程把鎖釋放,才可以繼續(xù)操作叼架。
市面上常見的枷鎖方式有以下幾種:
1畔裕、@synchronized關(guān)鍵字鎖
2、NSLock 對(duì)象鎖(NSOperation&NSOperationQueue)
3乖订、NSRecursiveLock 遞歸鎖
4扮饶、NSCondition斷言
5、NSConditionLock 條件鎖
6乍构、pthread_mutex 互斥鎖(C語(yǔ)言)
7甜无、dispatch_semaphore 信號(hào)量(GCD)
8、OSSpinLock(效率最快 有安全問(wèn)題)