1.請簡述你對工廠方法的理解?mysql
工廠Mycontrol,設計控件是用到工廠設計模式。類簇相似於工廠設計模式;工廠模式就是定義建立對象的接口,讓子類決定實例化哪個類。這樣,類的實例化就推遲到了子類程序員
2.UITableView有哪些優化方式?web
UITableView的優化主要從三個方面入手:面試
• 提早計算並緩存好高度(佈局),由於heightForRowAtIndexPath:是調用最頻繁的方法;sql
• 異步繪製,遇到複雜界面,遇到性能瓶頸時,可能就是突破口;數據庫
• 滑動時按需加載,這個在大量圖片展現,網絡加載的時候很管用!(SDWebImage已經實現異步加載,配合這條性能槓槓的)。設計模式
3.你如何理解block,block有什麼用途?數組
• 咱們能夠把Block當作Objective-C的匿名函數。Block容許開發者在兩個對象之間將任意的語句當作數據進行傳遞,每每這要比引用定義在別處的函數直觀。另外,block的實現具備封閉性(closure),而又可以很容易獲取上下文的相關狀態信息。緩存
• block是代碼塊,其本質和變量相似。不一樣的是代碼塊存儲的數據是一個函數體。使用Block,就能夠像其餘標準函數同樣,傳入參數,並獲得返回值。網絡
做爲OC對象的屬性,實現對象之間的傳值 • Block能夠看作是一個變量,所以能夠做爲OC對象的屬性
4.請問怎樣可以保證定位更省電?
1.開啓開始定位以後,不關閉,讓其持續定位
2.設置距離篩選器:座標移動到指定距離纔會調用代理方法
3.設置精準度:經過下降計算的過程(GPS),來達到省電的目的
5.請簡述NSUserDefaults的使用場景和 使用注意事項?
SUserDefaults適合存儲輕量級的數據,他不只能夠存儲基本數據類型,還能夠存儲NSNumber(Integer、Float、Double),NSString,NSDate,NSArray,NSDictionary,BOOL類型。
可是NSUserDefaults不能存儲自定義的類對象,若把一個對象存儲到NSUserDefaults會報錯。聰明的人會把對象放進數組,再把數組存入NSUserDefaults,不過這樣作事錯誤的,由於數組中包含了自定義對象。
若要在NSUserDefaults中存入自定義對象,則對象須要遵循NSCoding協議,並實現encodeWithCoder方法和initWithCoder方法。具體參考http://my.oschina.NET/u/1245365/blog/294449
值得一提的是,我發現類型爲NSNull的空數據也是沒法存入NSUserDefaults的。若數據中有NSNull類型空數據,把它置nil便可存入NSUserDefaults。
總之,NSUserDefaults是一種操做簡單的數據庫。
6.iOS中數據庫使用什麼技術實現的 ?
使用Sqlite和CoreData實現的
7.iOS中如何實現數據模型的存儲?
歸檔也是iOS提供給開發者的一種數據存儲的方式,事實上,幾乎全部的數據類型均可以經過歸檔來進行存取。其存儲與讀取的過程,主要封裝在兩個類中:NSKeyedArchiver和NSKeyedUnarchiver
8.爲何說Objective-C是一門動態的語言?
Objective-C是動態語言,它並不是經過調用類的方法來執行功能,而是給對象發送消息,
對象在接收到消息以後會去找匹配的方法來運行。
9.講一下MVC和MVVM,MVP?
1.MVC做爲老牌架構, 優勢在於將業務場景按展現數據類型劃分出多個模塊, 每一個模塊中的C層負責業務邏輯和業務展現, 而M和V應該是互相隔離的以作重用, 另外每一個模塊處理得當也能夠做爲重用單元. 拆分在於解耦, 順便作了減負, 隔離在於重用, 提高開發效率. 缺點是沒有區分業務邏輯和業務展現, 對單元測試不友好.
2.MVP做爲MVC的進階版, 提出區分業務邏輯和業務展現, 將全部的業務邏輯轉移到P層, V層接受P層的數據更新通知進行頁面展現. 優勢在於良好的分層帶來了友好的單元測試, 缺點在於分層會讓代碼邏輯優勢繞, 同時也帶來了大量的代碼工做, 對程序員不夠友好.
3.MVVM做爲集大成者, 經過數據綁定作數據更新, 減小了大量的代碼工做, 同時優化了代碼邏輯, 只是學習成本有點高, 對新手不夠友好.
4.MVP和MVVM由於分層因此會創建MVC兩倍以上的文件類, 須要良好的代碼管理方式.
5.在MVP和MVVM中, V和P或者VM之間理論上是多對多的關係, 不一樣的佈局在相同的邏輯下只須要替換V層, 而相同的佈局不一樣的邏輯只須要替換P或者VM層. 但實際開發中P或者VM每每由於耦合了V層的展現邏輯退化成了一對一關係(好比SceneA中須要顯示"xxx+Name", VM就將Name格式化爲"xxx + Name". 某一天SceneB也用到這個模塊, 全部的點擊事件和頁面展現都同樣, 只是Name展現爲"yyy + Name", 此時的VM由於耦合SceneA的展現邏輯, 就顯得比較尷尬), 針對此類狀況, 一般有兩種辦法, 一種是在VM層加狀態進而判斷輸出狀態, 一種是在VM層外再加一層FormatHelper. 前者可能由於狀態過多顯得代碼難看, 後者雖然比較優雅且拓展性高, 可是過多的分層在數據還原時就略顯笨拙, 你們應該按需選擇.
這裏隨便瞎扯一句, 有些文章上來就說MVVM是爲了解決C層臃腫, MVC難以測試的問題, 其實並非這樣的. 按照架構演進順序來看, C層臃腫大部分是沒有拆分好MVC模塊, 好好拆分就好了, 用不着MVVM. 而MVC難以測試也能夠用MVP來解決, 只是MVP也並不是完美, 在VP之間的數據交互太繁瑣, 因此才引出了MVVM. 當MVVM這個徹底體出現之後, 咱們從結果看起源, 發現它作了好多事情, 其實並非, 它的前輩們付出的努力也並很多!
10.爲何在默認狀況下沒法修改被block捕獲的變量? __block都作了什麼?
若是是用block(用static也能夠)修飾的局部變量,在block內部訪問的話,而是把這個局部變量的地址傳遞過去了,因此會跟蹤這個局部變量的變化,而且能夠修改,
若是block內部引用的變量是全局變量的話,那麼在block內部訪問,他也是把這個變量的地址傳遞過去了.。
11.模擬一下循環引用的一個狀況?block實現界面反向傳值如何實現?
ClassA和ClassB分屬兩個不一樣的線程,ClassB一般由ClassA發起請求建立,並由ClassA使用,ClassB則會在必要時通知ClassA一些事件。二者中各保留了對方的一個引用計數指針RefPtr。
若是在析構時釋放成員變量的話,就會發生循環引用的問題,致使兩個對象釋放失敗。
block的回調的使用步驟
1.聲明 : 在誰那裏調用就在誰那裏聲明
實現代碼
typedef void(^MyBlock)(NSString *name);//block的重命名
@property (nonatomic,copy) MyBlock block;//block的聲明
2.實現 : 誰要裝值就在誰那裏實現
實現代碼
SecondViewController *secondVC = [[SecondViewController alloc] init];
[self presentViewController:secondVC animated:YES completion:nil];//在這裏沒用導航控制器,用presentViewController來進入下一個視圖
//block實現
secondVC.block = ^void(NSString *name)
{
_label.text = name;
};//block的位置擺放很做用的,由於它是一個函數,不過必定不能放在使用它的對象的外面和前面就行了
3.調用 : 誰要傳值就在誰那裏調用
self.block(@"呵呵");//block的調用
總結一句話:block用在不一樣視圖控制器之間的值回傳,回傳還有代理、單例,在回傳中最簡單的就是用block了
*/
12.objc在向一個對象發送消息時,發生了什麼?
SomeClass * someObject; someObject = nil; [someObject doSomething];
就像這樣,向nil發送了doSomething;OC中nil是被當作0定義的。也就是說runtime要去獲取這個nil的信息,會去讀取內存中0的位置,這確定是不容許的,會返回nil,0,0.0等數據,根據返回值類型。
比較讓你混淆的是,殭屍對象。殭屍對象並非nil,殭屍對象是你的object被銷燬或者用於其餘地方了,可是指向它的指針還在。會發生向一個object發送一個它沒有的方法。
13.何時會報unrecognized selector錯誤?iOS有哪些機制來避免走到這一步?
對象未實現該方法。
對象已經被釋放。
使用[id respondsToSelector:]進行判斷。
Method resolution
objc運行時會調用+resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機會提供一個函數實現。若是你添加了函數,那運行時系統就會從新啓動一次消息發送的過程,不然 ,運行時就會移到下一步,消息轉發(Message Forwarding)。
返回Nil和self,去調用第三步methodSignatureForSelector和forwarInvocation;返回receiver,若是receiver有響應就直接處理,若是沒有就去對應的對象內去調用第三步;調用子類的函數,子類沒有進行這幾個方法的重載,在父類處理時返回子類,會死循環。
Fast forwarding
若是目標對象實現了-forwardingTargetForSelector:,Runtime 這時就會調用這個方法,給你把這個消息轉發給其餘對象的機會。 只要這個方法返回的不是nil和self,整個消息發送的過程就會被重啓,固然發送的對象會變成你返回的那個對象。不然,就會繼續Normal Fowarding。 這裏叫Fast,只是爲了區別下一步的轉發機制。由於這一步不會建立任何新的對象,但下一步轉發會建立一個NSInvocation對象,因此相對更快點。
Normal forwarding
這一步是Runtime最後一次給你挽救的機會。首先它會發送-methodSignatureForSelector:消息得到函數的參數和返回值類型。若是-methodSignatureForSelector:返回nil,Runtime則會發出-doesNotRecognizeSelector:消息,程序這時也就掛掉了。若是返回了一個函數簽名,Runtime就會建立一個NSInvocation對象併發送-forwardInvocation:消息給目標對象。
14.可否向編譯後獲得的類中增長實例變量?可否向運行時建立的類中添加實例變量?爲何?
解釋:
2.運行時建立的類是能夠添加實例變量,調用class_addIvar函數.可是的在調用objc_allocateClassPair以後,objc_registerClassPair以前,緣由同上.
15.runtime如何實現weak變量的自動置nil?
runtime 對註冊的類, 會進行佈局,對於 weak 對象會放入一個 hash 表中。 用 weak 指向的對象內存地址做爲 key,當此對象的引用計數爲0的時候會 dealloc,假如 weak 指向的對象內存地址是a,那麼就會以a爲鍵, 在這個 weak 表中搜索,找到全部以a爲鍵的 weak 對象,從而設置爲 nil。
16.給類添加一個屬性後,在類結構體裏哪些元素會發生變化?
定義結構體會
17.runloop是來作什麼的?runloop和線程有什麼關係?主線程默認開啓了runloop麼?子線程呢?
用來控制一些特殊操做只能在指定模式下運行,通常能夠經過指定操做的運行mode 來控制執行時機,以提升用戶體驗
系統默認註冊了 5 個 Mode
kCFRunLoopDefaultMode:App 的默認 Mode,一般主線程是在這個 Mode
下運行,對應 OC 中的:NSDefaultRunLoopMode
UITrackingRunLoopMode:界面跟蹤 Mode,用於 ScrollView 追蹤觸摸滑
動,保證界面滑動時不受其餘 Mode 影響
kCFRunLoopCommonModes:這是一個標記 Mode,不是一種真正的 Mode,事件
能夠運行在全部標有 common modes 標記的模式中,對應 OC 中的
NSRunLoopCommonModes , 帶 有 common modes 標 記 的 模 式 有 :UITrackingRunLoopMode 和 kCFRunLoopDefaultMode
UIInitializationRunLoopMode:在啓動 App 時進入的第一個 Mode,啓動完成後
就再也不使用
GSEventReceiveRunLoopMode:接受系統事件的內部 Mode,一般用不到
RunLoop只能運行在一種mode下,若是要換mode,當前的loop也須要停下重啓成新的。利用這個機制,ScrollView滾動過程當中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode會切換到UITrackingRunLoopMode來保證ScrollView的流暢滑動:只能在NSDefaultRunLoopMode模式下處理的事件會影響scrllView的滑動。
若是咱們把一個NSTimer對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環中的時候, ScrollView滾動過程當中會由於mode的切換,而致使NSTimer將再也不被調度。
同時由於mode仍是可定製的,因此:
Timer計時會被scrollView的滑動影響的問題能夠經過將timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)來解決。
20.蘋果是如何實現Autorelease Pool的?每個線程的 autoreleasepool 其實就是一個指針的堆棧;
每個指針表明一個須要 release 的對象或者 POOL_SENTINEL(哨兵對象,表明一個 autoreleasepool 的邊界);
一個 pool token 就是這個 pool 所對應的 POOL_SENTINEL 的內存地址。當這個 pool 被 pop 的時候,全部內存地址在 pool token 以後的對象都會被 release ;
這個堆棧被劃分紅了一個以 page 爲結點的雙向鏈表。pages 會在必要的時候動態地增長或刪除;
Thread-local storage(線程局部存儲)指向 hot page ,即最新添加的 autoreleased 對象所在的那個 page 。
21.isa指針?(對象的isa,類對象的isa,元類的isa都要說)
1、類的基本概念:
一、類其實也是一個對象, 這個對象會在這個類第一次被使用的時候建立
二、只要有了類對象, 未來就能夠經過類對象來建立實例對象
三、實例對象中有一個isa指針, 指向建立本身的類對象
四、類對象中保存了當前對象全部的對象方法
五、當給一個實例對象發送消息的時候, 會根據實例對象中的isa指針去對應的類對象中查找
六、全部類對象的繼承關係就是元類對象的繼承關係
2、isa指針
1.每個對象都包含一個isa指針.這個指針指向當前對象所屬的類。
2.[d bark];表示給d所指向的對象發送一條bark消息,調用對象的bark方法,此時對象會順着內部的isa指針找到存儲於類中的方法並執行。
3.isa是對象中的隱藏指針,指向建立這個對象的類。
4.經過isa指針咱們能夠在運行的時候知道當前對象是屬於那個類。
3、元類
一、元類的定義:元類是類對象的類,每一個類都有本身獨一無二的元類,即
(1)當你給對象發送消息時,消息是在尋找這個對象的類的方法列表。
(2)當你給類發消息時,消息是在尋找這個類的元類的方法列表。
元類是必不可少的,由於它存儲了類的類方法。每一個類都必須有獨一無二的元類,由於每一個類都有獨一無二的類方法。
二、元類的類:
(1)元類,就像類同樣,它也是一個對象,也能夠調用它的方法。這就意味着他必須也有一個類。
(2)全部的元類都使用根元類(繼承體系中處於頂端的類的元類)做爲他們的類。即全部NSObject的子類的元類都會以NSObject的元類做爲他們的類。
(3)全部的元類使用根元類做爲他們的類,根元類的元類則就是它本身。也就是說基類的元類的isa指針指向他本身。
22.介紹一下分類,能用分類作什麼?內部是如何實現的?它爲何會覆蓋掉原來的方法?
由於分類方法加入類中這一操做是在運行期系統加載分類時完成的,運行期系統會把分類中所實現的每個方法都加入類的方法列表中,具體步驟以下:
category的實例方法、協議以及屬性添加到類上
category的類方法和協議添加到類的metaclass上
category的方法被放到了新方法列表的前面,而原來類的方法被放到了新方法列表的後面,因此category的方法會「覆蓋」掉原來類的同名方法。
23.運行時能增長成員變量麼?能增長屬性麼?若是能,如何增長?若是不能,爲何?
不少人在面試的時候都會被問到Category,既然容許用Category給類增長方法和屬性,那爲何不容許增長成員變量?
在Objective-C提供的runtime函數中,確實有一個class_addIvar()函數用於給類添加成員變量,可是閱讀過蘋果的官方文檔的人應該會看到:
This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.
大概的意思說,這個函數只能在「構建一個類的過程當中」調用。一旦完成類定義,就不能再添加成員變量了。通過編譯的類在程序啓動後就被runtime加載,沒有機會調用addIvar。程序在運行時動態構建的類須要在調用objc_registerClassPair以後才能夠被使用,一樣沒有機會再添加成員變量。
在 Objective-C 中向 nil 發送消息是徹底有效的——只是在運行時不會有任何做用:
Person * motherInlaw = [[aPerson spouse] mother];
若是 spouse 對象爲 nil,那麼發送給 nil 的消息 mother 也將返回 nil。