昨天進(jìn)行了360的視頻面試伪很,很遺憾的沒有進(jìn)戚啥。很多問題的答案就在嘴邊,可是就是說不出來锉试,很遺憾猫十。總結(jié)下來還是自己的準(zhǔn)備不夠充分呆盖。下面把還記得的問題放上來拖云,并發(fā)誓下次遇到以下題目一定答得上來。
(ps:下面的回答都是我的個人總結(jié)应又,很有可能會有遺漏宙项,所以有問題可以幫我指出一下,謝謝)
面試題
第一題問題
說說oc語言和別的語言的區(qū)別株扛。
第一題分析
遇到這道題目的時候尤筐,我就說了c語言和oc的區(qū)別。直到面試官提示了一下洞就,問我為什么大家都說oc是一門動態(tài)的語言盆繁,我才意識到該說一下對runtime的理解了。
第一題答案
[receiver message];
// 底層運(yùn)行時會被編譯器轉(zhuǎn)化為:
objc_msgSend(receiver, selector)
之所以說它是動態(tài)的范舀,是因?yàn)樗鼤⒁恍┕ぷ鞣旁诖a運(yùn)行時才處理而并非編譯時合是。也就是說,有很多類和成員變量在我們編譯的時候是不知道的锭环,而在運(yùn)行時聪全,我們所編寫的代碼會轉(zhuǎn)換成完整的確定的代碼運(yùn)行。
第二題問題
既然你說runtime會把方法調(diào)用轉(zhuǎn)化成objc_msgSend(receiver, selector)
辅辩,那說說消息機(jī)制的流程难礼。
第二題分析
因?yàn)榈谝活}的時候我有提到消息機(jī)制,所以面試官才會這樣問玫锋。但是這道題目我還是胸有成竹的蛾茉。
第二題答案
首先說一下類的實(shí)例的結(jié)構(gòu)體中其實(shí)只有一個指向其類對象的指針。
typedef struct objc_object *id;
struct objc_object {
Class isa;
};
再說一下類對象結(jié)構(gòu)體中有super_class撩鹿、methodLists谦炬、cache等元素。
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;
然后可以開始表演了:
1.首先三痰,編譯器將代碼[receiver message];
轉(zhuǎn)化為objc_msgSend(receiver, selector)
吧寺。
2.然后會receiver的isa指針找到obj對應(yīng)的class窜管。在class中先去cache中通過SEL查找對應(yīng)函數(shù)method散劫。
3.若cache中未找到。再去methodList中查找幕帆,若methodlist中未找到获搏,則去superClass中查找。若能找到,則將method加入到cache中常熙,以方便下次查找纬乍,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行。
4.如果都沒有找到裸卫,runtime 會調(diào)用 resolveInstanceMethod: 或 resolveClassMethod: 來給我們一次動態(tài)添加方法實(shí)現(xiàn)的機(jī)會仿贬。我們需要用 class_addMethod 函數(shù)完成向特定類添加特定方法實(shí)現(xiàn)的操作。
(如果了解元類的概念墓贿,也可以扯一點(diǎn)類方法的調(diào)用流程茧泪,其實(shí)類似)
第三題問題
既然你前面一直有提到方法,那說說SEL與IMP的差別吧聋袋。
第三題分析
岸游啊?我有提到IMP嗎幽勒?這下完了嗜侮,我該怎么編。啥容。锈颗。所以在面試的時候我只說了SEL。
第三題答案
SEL是“selector”的一個類型咪惠,表示方法的名字宜猜。就像這樣,SEL message = @selector(message);
而IMP是指向函數(shù)的指針硝逢,我把他理解為它就是一個函數(shù)姨拥,就是即將要執(zhí)行的那個函數(shù)。
這兩者估計(jì)就是通過一張表來相對應(yīng)的渠鸽。相當(dāng)于說SEL是key叫乌,而IMP是value。這個我真的不清楚了徽缚。
第四題問題
說一下你對內(nèi)存管理的理解吧憨奸。
第四題分析
就是這道題,明明都知道凿试,卻不知如何開口排宰,僵硬了很久。
第四題答案
先放出內(nèi)存管理四大原則:
1.自己生成的對象自己持有:alloc/new/copy等
2.非自己生成的對象自己也能持有:retain
3.不再需要自己持有的對象時釋放:release
4.自己不持有的對象不能釋放
然后說一下必須得提的引用計(jì)數(shù):?系統(tǒng)通過引用計(jì)數(shù)來管理內(nèi)存那婉。系統(tǒng)判斷對象要不要回收的唯一依據(jù)就是計(jì)數(shù)器是否為0板甘。當(dāng)一個對象被初始化的時候,他的引用計(jì)數(shù)是1详炬,如果調(diào)用retain方法盐类,引用計(jì)數(shù)會變?yōu)?,這時調(diào)用兩次release引用計(jì)數(shù)會變?yōu)?,對象會被釋放并調(diào)用dealloc方法在跳。
可以提一下內(nèi)存管理的范圍:任何繼承NSObject的對象枪萄,對其他的基本數(shù)據(jù)類型無效。那是因?yàn)閷ο蠛推渌麛?shù)據(jù)類型在系統(tǒng)中的存儲空間不一樣猫妙。前者放在堆中瓷翻,后者主要在棧中。
最后在提一下ARC環(huán)境中割坠,系統(tǒng)仍然是通過引用計(jì)數(shù)來管理內(nèi)存逻悠,但是當(dāng)我們不再需要對象時不需要自己手動release,系統(tǒng)會幫我們釋放韭脊。
第五題問題
有哪些情況會出現(xiàn)內(nèi)存泄漏童谒。
第五題分析
這道題目我就只說出了一個循環(huán)引用,別的一下子沒想到沪羔,估計(jì)面試官很不滿意饥伊。(反思:這道題目在一家公司的筆試中以簡答題的形式出現(xiàn)過,我當(dāng)時也只是寫了循環(huán)引用蔫饰,結(jié)束后立馬忘記了這件事了所以說自己不重視也是很大的問題)
第五題答案
1.block導(dǎo)致的循環(huán)引用
block中導(dǎo)致的內(nèi)存泄漏常常是因?yàn)閺?qiáng)引用互相之間持有而發(fā)生了循環(huán)引用無法釋放琅豆。
self.block = ^{
[self doSomething];
};
這是最簡單的情況,self持有block篓吁,block又持有self茫因。解決方法是__weak __typeof(self) weakSelf = self;
。這樣就打破了循環(huán)引用了杖剪。
2.NSTimer導(dǎo)致的內(nèi)存泄漏
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(log) userInfo:nil repeats:YES];
像我這樣初始化一個timer對象時冻押,self就強(qiáng)引用timer,timer又強(qiáng)引用target盛嘿,導(dǎo)致了循環(huán)引用洛巢。其實(shí)解決方法很簡單,就是[self.timer invalidate];
次兆。但是這里需要注意的是不能在控制器的dealloc方法中調(diào)用停止方法稿茉,因?yàn)槿绻鹴imer不停止,就根本進(jìn)不去dealloc方法芥炭。
注意
這里還有一點(diǎn)要提一下漓库,那就是為什么不能和解決block循環(huán)應(yīng)用的方法一樣,用_weak方法园蝠。這樣timer不就弱引用self了嗎渺蒿。像下面這樣,美滋滋砰琢。
__typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(log) userInfo:nil repeats:YES];
在block中,block是對變量進(jìn)行捕獲,意思是對使用到的變量進(jìn)行拷貝操作,注意是拷貝的不是對象,而是變量自身,拿上面的來說,block中只是對變量weakSelf拷貝了一份,也就是說,block中也定義了一個weak對象,相當(dāng)于,在block的內(nèi)存區(qū)域中,定義了一個__weak blockWeak對象,然后執(zhí)行了blockWeak = weakSelf蘸嘶。所以這里并沒有引起對象的引用計(jì)數(shù)的變化,所以沒有問題良瞧。
回到NSTimer中陪汽,根據(jù)target的說明:
The timer maintains a strong reference to this object until it (the timer) is invalidated
這里的target是需要強(qiáng)引用的训唱,也就是說就算你傳過去一個weakSelf,系統(tǒng)也會把它轉(zhuǎn)換成強(qiáng)引用:__strong strongSelf = weakSelf
挚冤。因此解決不了問題况增。
3.感謝RITL的補(bǔ)充。
__weak __typeof__(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey" object:nil queue:nil usingBlock:^(NSNotification *note) {
__typeof__(self) strongSelf = weakSelf;
[strongSelf dismissModalViewControllerAnimated:YES];
}];
這是通知方法導(dǎo)致的循環(huán)引用训挡,原因和上面的block類似澳骤。解決方法也是一樣的。
4.聲明delegate時如果使用了strong或者retain澜薄,十有八九會出現(xiàn)循環(huán)引用为肮,所以delegate一定要用weak。
5.C對象是需要自己手動free的肤京,所以忘記釋放可能會導(dǎo)致內(nèi)存泄漏颊艳。
第六題問題
前面你有提到可以用_weak來解決block中的循環(huán)引用,還有別的方法嗎忘分。
第六題答案
1.在ARC 環(huán)境下且 iOS 5.0 以上的版本棋枕,完全可以用 _weak解決強(qiáng)引用循環(huán)的問題。
2.在ARC環(huán)境下但是要兼容 iOS 4.x 的版本妒峦,用 _unsafe_unretained 解決強(qiáng)引用循環(huán)的問題重斑。
_unsafe_unretained 修飾的變量就相當(dāng)于一個普通的指針,但是需要注意的是它指向的對象被釋放時肯骇,這個指針不會被設(shè)置 nil窥浪,就成了野指針,就不能再用它了笛丙,會崩潰的寒矿。所以,除非是要兼容 4.x 系統(tǒng)若债,否則就別用了符相。
3.在 MRC 環(huán)境下,用 _block 解決強(qiáng)引用循環(huán)的問題蠢琳。
因?yàn)樵?ARC 下啊终,_block 修飾的變量在 Block 塊中會被 retain,而在 MRC 下傲须,不會 retain蓝牲。但是在 MRC 下用 _block 有一個問題,不會對已經(jīng)釋放的對象自動置為 nil泰讽,這時候在某些異步調(diào)用的情況下例衍,當(dāng) Block 塊中的代碼被執(zhí)行時昔期,就可能出現(xiàn)野指針的情況而引發(fā)問題。這種情況我們可以通過 malloc_zone_from_ptr 這個函數(shù)來檢查指針是否為野指針佛玄。示例代碼如下:
__block typeof(self) blockSelf = self;
self.block = ^{
if (!malloc_zone_from_ptr(blockSelf)) {
return;
}
[blockSelf doSomething];
}
第七題問題
控制器Apush到B后硼一,有哪些方法可以讓B的數(shù)據(jù)傳遞到A。
第七題分析
這道題我就答了block梦抢、delegate般贼、通知。然而這些都不重要奥吩,面試官問這道題的目的其實(shí)就是為了引出下一題的:咔!
第七題答案
其實(shí)我的說這些已經(jīng)差不多夠了霞赫,如果硬要再說幾個的話腮介,KVO,或者NSUserdefault持久化數(shù)據(jù)也是可以的端衰。(由于這些比較簡單叠洗,我就不寫在這里浪費(fèi)篇幅了。)
第八題問題
說說KVO的原理吧靴迫。
第八題分析
在上一題因?yàn)槲覜]說KVO惕味,所以他問我KVO不行嗎,我說也可以啊玉锌,然后就有這一題了名挥。都是套路。不過還好我看過一些原理主守,不然這題也是編不出來的禀倔。。
第八題答案
首先KVO是oc對觀察者設(shè)計(jì)模式的一種實(shí)現(xiàn)参淫。它是基于runtime實(shí)現(xiàn)的救湖。
下面是底層實(shí)現(xiàn)流程:(以Teacher類為例,teacher為實(shí)例涎才,有一個name屬性)
1.當(dāng)teacher被觀察時鞋既,teacher的 isa 指針從指向原來的Teacher,被KVO機(jī)制修改為指向系統(tǒng)新創(chuàng)建的子類 NSKVONotifying_Teacher類耍铜。這個時候邑闺,teacher就是NSKVONotifying_Teacher的實(shí)例了。
2.在NSKVONotifying_Teacher類中棕兼,系統(tǒng)會重寫setName方法陡舅,并在setName方法中調(diào)用下面兩個方法。
[self willChangeValueForKey:@"name"];
[self didChangeValueForKey:@"name"];
3.然后就會調(diào)用observeValueForKey:ofObject:change:context:
方法了伴挚。
這張圖很好得說明了問題靶衍。
(ps:所以說灾炭,只有調(diào)用set方法的時候才會觸發(fā)KVO,如果直接
_name = @"YQ"
颅眶,是不會觸發(fā)KVO的蜈出,因?yàn)槟銢]有用set方法)
第九題問題
現(xiàn)在在TableViewCell上有一個UILabel,UILabel上寫是倒計(jì)時帚呼,倒計(jì)時用NSTimer實(shí)現(xiàn)掏缎,現(xiàn)在滾動tableView皱蹦,UILabel上的text會變嗎煤杀。
第九題分析
這道題目是回答的最順的。因?yàn)橐郧坝醒芯窟^RunLoop沪哺。
第九題答案
不會變沈自,因?yàn)閠ableView滾動的事件屬于UITrackingRunLoopMode,而timer默認(rèn)加入到kCFRunLoopDefaultMode中辜妓,在每次調(diào)用 RunLoop 的主函數(shù)時枯途,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode籍滴。所以當(dāng)滾動時酪夷,定時器就不起作用了。解決辦法為修改timer的模式為NSRunLoopCommonModes孽惰。
具體可以看這篇文章:RunLoop入門 看我就夠了
第十題問題
frame和bouns的區(qū)別黍判。什么時候frame和bouns的高寬不相等喳瓣。
第十題分析
這道題目又是一臉懵逼。。以前好像沒碰到過這種事情吧嗽测。□锝幔總不能傻在那里吧劫狠,我就說了他們的區(qū)別。骚揍。
第十題題答案
frame: view在父view坐標(biāo)系統(tǒng)中的位置和大小字管。(參照點(diǎn)是,父親的坐標(biāo)系統(tǒng))
bounds:view在本地坐標(biāo)系統(tǒng)中的位置和大小信不。(參照點(diǎn)是嘲叔,本地坐標(biāo)系統(tǒng),就相當(dāng)于ViewB自己的坐標(biāo)系統(tǒng)浑塞,以0,0點(diǎn)為起點(diǎn))
然后我的理解是借跪,父視圖如果設(shè)置了自己的bouns,會影響到子視圖的位置酌壕。比如父視圖view.bounds = CGRectMake(-30, -30, 200, 200);
就會使得view的左上角的坐標(biāo)從(0,0)變成(-30,-30)掏愁,也就是說歇由,view的子視圖如果設(shè)置childView.frame = CGRectMake(0, 0, 100, 100);
,那么childView會向右下方向各偏移30像素果港。
然而什么時候高寬不相等沦泌。。辛掠。表示還是不清楚
感謝Hall_of_fame的補(bǔ)充谢谦。
下面是我根據(jù)Hall_of_fame的評論做的試驗(yàn):
代碼很簡單,初始化視圖時候打印一次萝衩,點(diǎn)擊屏幕旋轉(zhuǎn)視圖后再打印一次回挽,注意猩谊,只是旋轉(zhuǎn)父視圖千劈,子視圖沒動。
可以發(fā)現(xiàn)旋轉(zhuǎn)后只有父視圖的frame發(fā)生了變化喜滨。
結(jié)論:
視圖旋轉(zhuǎn)只影響視圖本身以及子視圖的視覺效果,視圖旋轉(zhuǎn)改變了其在父視圖中的位置但并未改變自身尺寸撤防,也沒有改變子視圖在其坐標(biāo)系的位置虽风。另外旋轉(zhuǎn)是圍繞center為中心進(jìn)行的,只有旋轉(zhuǎn)的視圖自身frame發(fā)生改變即碗,bounds和center不受影響焰情,子視圖的坐標(biāo)系均不受影響。
再次感謝Hall_of_fame剥懒。
第十一題問題
說說進(jìn)程和線程的區(qū)別内舟。
第十一題答案
1.線程是指進(jìn)程內(nèi)的一個執(zhí)行單元。
2.一個程序就是一個進(jìn)程初橘,而一個進(jìn)程至少有一個線程验游。
3.同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。
4.不僅進(jìn)程之間可以并發(fā)執(zhí)行保檐,同一個進(jìn)程的多個線程之間也可以并發(fā)執(zhí)行耕蝉。
第十二題問題
NSOprationQueue 與 GCD 你平時一般用哪個。NSOprationQueue 與 GCD 的區(qū)別夜只。
第十二題分析
這道題目我回答的是GCD 垒在,然后他就問我GCD怎么實(shí)現(xiàn)任務(wù)順序執(zhí)行或者說依賴執(zhí)行,怎么知道任務(wù)什么時候完成扔亥。額场躯,我說這兩個一般都用NSOprationQueue 比較好實(shí)現(xiàn)的谈为。然而面試官抓著不放GCD,我表示我不會額踢关。伞鲫。。
第十二題答案
1.GCD是底層的C語言構(gòu)成的API签舞,而NSOperationQueue是進(jìn)行過封裝的秕脓,是面向?qū)ο蟮摹?br>
2.GCD的執(zhí)行速度比NSOperationQueue快。
3.在NSOperationQueue可以隨時取消已經(jīng)設(shè)定要準(zhǔn)備執(zhí)行的任務(wù)儒搭,而GCD如果要停止已經(jīng)加入queue的block比較麻煩吠架。
4.NSOperation能夠方便地設(shè)置依賴關(guān)系,我們可以讓一個Operation依賴于另一個Operation师妙,這樣的話盡管兩個Operation處于同一個并行隊(duì)列中诵肛,但前者會直到后者執(zhí)行完畢后再執(zhí)行屹培;
5.使用NSOperation可以方便知道Operation何時結(jié)束默穴,比GCD更加有效地掌控我們執(zhí)行的后臺任務(wù)。
使用場合:
任務(wù)之間不太相互依賴:GCD
任務(wù)之間有依賴或要監(jiān)聽任務(wù)的執(zhí)行情況:NSOperationQueue
總結(jié)
以上就是這次面試的大數(shù)題目褪秀,還有一些題目因?yàn)楸容^簡單蓄诽,所以現(xiàn)在也忘記了題目是什么∶铰穑總的來說仑氛,這次面試也不是很難,沒有問比較深的知識闸英,主要還是自己準(zhǔn)備不夠才導(dǎo)致失敗锯岖。
還有一點(diǎn)就是自己不太會的知識盡量避免提到,不然被面試官聽到很有可能他就有了興趣甫何。