1.什么是函數(shù)式編程?什么是鏈式編程思想?
1.編程思想的由來:我們在開發(fā)中會遇到各種各樣的問題,經(jīng)常思考如何快速完成這個需求,這樣就會慢慢形成快速完成這些需求的思想,
2.面向過程:處理事情以過程為核心,一步一步實現(xiàn)
3.鏈式編程思想:將多個操作(多行代碼)通過點語法(.)鏈接成一句代碼,代碼可讀性好
3.1.鏈式變成思想特點:方法的返回值是block,block必須有返回值(對象本身),block(參數(shù)),代表有masonry框架
4.響應(yīng)式編程思想:不需要考慮調(diào)用順序,只需要知道結(jié)果,代表有KVO運用
4.1函數(shù)式編程思想:把操作盡量寫成一系列嵌套的函數(shù)或者方法調(diào)用
4.2函數(shù)式編程思想的本質(zhì):就是在方法里面?zhèn)魅隻lock,方法中嵌套block調(diào)用,把代碼聚合起來管理
4.3函數(shù)式編程的特點:每個方法必須有返回值(對象本身),把函數(shù)或者block當做參數(shù),block參數(shù)(需要操作的值)block(操作結(jié)果),代表有ReactiveCocoa
2.為什么說OC是一門動態(tài)語言?
1.OC類的類型和數(shù)據(jù)變量的類型都是在運行時確定的,而不是在編譯時確定的,
2.例如:多態(tài)性:我們可以使用父類指針指向子類對象,并且可以使用子類的方法,運行時的特性可以使我們動態(tài)加方法或者替換方法
3.講一下MVC,MVVM,MVP?
1.MVC: 簡單來說就是,邏輯,視圖,數(shù)據(jù)進行分層,實現(xiàn)解耦
2.MVVM:是Model-View-ViewMode模式的簡稱,由視圖,是視圖模型,模型三部分組成,比MVC更加釋放控制器的臃腫,將一部分邏輯(耗時,公共方法,網(wǎng)絡(luò)請求)和數(shù)據(jù)處理從控制器搬運到ViewMode中,
2.1.低耦合:View可以獨立于Model變化和修改,一個ViewMode可以綁定到不同View上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
2.2.可重用性,可以把一些視圖的邏輯放在ViewModel上。
2.3.獨立開發(fā):開發(fā)人員可以專注于業(yè)務(wù)邏輯的開發(fā),設(shè)計人員可以專注界面的設(shè)計。
4.為什么代理使用weak?代理的delegate和dataSource有什么區(qū)別?block和代理的區(qū)別?
1.代理使用weak修飾,原因如下:
1.1.使用weak修飾是為了避免循環(huán)引用,
1.2.當使用weak修飾時,對象釋放的時候系統(tǒng)會對屬性賦值nil,OC的特性就是對nil對象發(fā)送消息也就會調(diào)用方法不會cash,
1.3.delegate傳遞的是事件,代理可以讓A對象通知B對象,A發(fā)生的變化,前提是B遵循了A的代理,并且實現(xiàn)了A的代理方法
2.dataSource傳遞的是數(shù)據(jù),如果A聲明了數(shù)據(jù)源,我們創(chuàng)建A對象的時候,我們就該實現(xiàn)數(shù)據(jù)源。
3.代理和block的區(qū)別:相同點:代理和block基本用來倒序傳值,都要注意避免循環(huán)引用,我們?nèi)ナ褂玫臅r候都需要判斷是否實現(xiàn)
4.不同點:代理使用weak修飾,代理必須先聲明方法,block是用copy修飾,block保存的是一段代碼,其實就是一個函數(shù),并且可以自動捕捉自動變量,如果想修改這個變量必須使用__block
5.屬性的實質(zhì)是什么?包含哪些部分?默認關(guān)鍵字有哪些?@dynamic關(guān)鍵字和@synthesize用來做什么?
1.屬性的實質(zhì)是描述類的特征,主要包含三部分,帶下劃線的成員變量,get,set方法,
2.默認的關(guān)鍵字:readwrite,assign,atomic,是針對基本類型(NSInteger, BOOL, NSUInteger, int, 等),
strong, readwrite, atomic是針對引用類型,(NSString, NSArray, NSDictory等),
3.@dynamic修飾的屬性,getter和setter方法編譯器不會幫你自動生成,必須是自己實現(xiàn),
4.@synthesize:修飾的屬性,其getter和setter方法編譯器是會自動幫你生成,不必自己實現(xiàn)。且指定與屬性相對應(yīng)的成員變量。
6.NSString為什么使用copy關(guān)鍵字?如果使用strong有什么問題?
1.可變類型NSMutableArray,NSMutableString等,是不可邊類型(NSString,NSArray等)的子類,因為多態(tài),我們可以使用不可變類型去接受可變類型。
2.當我們使用strong修飾不可變類型A時,并且使用B可變類型給A賦值,再去修改可變類型B的時候,A所指向的值也會改變,引用strong只會讓創(chuàng)建的對象引用計數(shù)+1,并返回當前對象的地址,當我們修改B指向的內(nèi)容的時候,A指向的內(nèi)容也會改變,因為他們指向的內(nèi)存地址相同,是同一份內(nèi)容.
3.當使用copy修飾不可變類型A時,并且使用可變類型B給A賦值,再去修改可變類型B的值,A的值不會改變,因為使用copy修飾的時候,會拷貝出一份內(nèi)容,并且返回指針給A,當我們修改B的時候A不會改變,因為A指向的內(nèi)存地址和B指向的內(nèi)存地址是不相同的,是兩份內(nèi)容,
4.copy修飾不可邊類型(NSString,NSArray等)的時候,且使用不可邊類型進行賦值,表示淺拷貝,只拷貝一份指針,和strong修飾一樣,當修飾的是可變類型(NSMutableArray,NSMutableString等)的時候,且使用可邊類型進行賦值,表示深拷貝,直接拷貝新一份內(nèi)容,到內(nèi)存中。表示兩份內(nèi)容。
7.如何令自己所寫的對象具有拷貝功能?
如果想讓自己的類具備copy方法,并返回不可邊類型,必須遵循nscopying協(xié)議,并且實現(xiàn)
- (id)copyWithZone:(NSZone *)zone
如果讓自己的類具備mutableCopy方法,并且放回可變類型,必須遵守NSMutableCopying,并實現(xiàn)- (id)mutableCopyWithZone:(nullable NSZone *)zone
注意:再此說的copy對應(yīng)不可邊類型和mutableCopy對應(yīng)不可邊類型方法,都是遵從系統(tǒng)規(guī)則而已。如果你想實現(xiàn)自己的規(guī)則,也是可以的。
8.為什么IBOutlet修飾的UIView也適用weak關(guān)鍵字?
在xib或者sb拖控件的時候,其實控件已經(jīng)加載到父控件的subviews數(shù)組里面,進行了強引用,即使使用weak也不會造成對象的釋放。
9.用StoryBoard開發(fā)界面有什么弊端?如何避免?
使用簡單邏輯頁面的跳轉(zhuǎn)是可以使用sb的,開發(fā)比較塊。
但是SB對于邏輯項目比較復(fù)雜的時候,開發(fā)起來比較慢。不適合多人合作開發(fā);也不利于版本的梗系和后期的維護。使用sb在項目變異編譯的時候,也都會直接加載到內(nèi)存中,造成內(nèi)存的浪費。
可以使用xib來代替,編輯復(fù)雜邏輯界面時候可以使用純碼編寫。
10.進程和線程的區(qū)別?同步異步的區(qū)別?并行和并發(fā)的區(qū)別?
進程:是具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運行活動,進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位.
線程:是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
同步:阻塞當前線程操作,不能開辟線程。
異步:不阻礙線程繼續(xù)操作,可以開辟線程來執(zhí)行任務(wù)。
并發(fā):當有多個線程在操作時,如果系統(tǒng)只有一個CPU,則它根本不可能真正同時進行一個以上的線程,它只能把CPU運行時間劃分成若干個時間段,再將時間 段分配給各個線程執(zhí)行,在一個時間段的線程代碼運行時,其它線程處于掛起狀。.這種方式我們稱之為并發(fā)(Concurrent)。
并行:當系統(tǒng)有一個以上CPU時,則線程的操作有可能非并發(fā)。當一個CPU執(zhí)行一個線程時,另一個CPU可以執(zhí)行另一個線程,兩個線程互不搶占CPU資源,可以同時進行,這種方式我們稱之為并行(Parallel)。
區(qū)別:并發(fā)和并行是即相似又有區(qū)別的兩個概念,并行是指兩個或者多個事件在同一時刻發(fā)生;而并發(fā)是指兩個或多個事件在同一時間間隔內(nèi)發(fā)生。在多道程序環(huán)境下,并發(fā)性是指在一段時間內(nèi)宏觀上有多個程序在同時運行,但在單處理機系統(tǒng)中,每一時刻卻僅能有一道程序執(zhí)行,故微觀上這些程序只能是分時地交替執(zhí)行。倘若在計算機系統(tǒng)中有多個處理機,則這些可以并發(fā)執(zhí)行的程序便可被分配到多個處理機上,實現(xiàn)并行執(zhí)行,即利用每個處理機來處理一個可并發(fā)執(zhí)行的程序,這樣,多個程序便可以同時執(zhí)行。
11.如何使用隊列來避免資源搶奪?
當我們使用線程訪問同一個數(shù)據(jù)的時候,可能造成數(shù)據(jù)的不準確性,這個時候我們可以使用線程鎖來綁定,也可以使用串行隊列完成,比如:fmdb就是使用FMDatabaseQueue,解決多線程搶奪資源
12.數(shù)據(jù)化持久存儲的方法
plist:存儲字典,數(shù)組比較好用
preference:偏好設(shè)置,實質(zhì)上也是plist
NSKeyedArchiver:歸檔,也可以使用存儲對象
sqlite:數(shù)據(jù)庫,經(jīng)常使用的第三方數(shù)據(jù)庫操作,比如fmdb
coreData:也是數(shù)據(jù)庫存儲,蘋果官方的

14.NSCache優(yōu)于NSDictionary的幾點?
1.NSCache是可以自動釋放內(nèi)存的
2.NSCache是線程安全的,我們可以在不同的線程中添加,刪除,查詢緩存的對象
3.一個緩存對象不會拷貝key對象
15.Designated Initializer (指定初始化函數(shù))使用需要注意什么?
1.子類如果有指定的初始化函數(shù),那么指定的初始化函數(shù)實現(xiàn)時必須調(diào)用它的直接父類的指定初始化函數(shù)。
2.如果子類有指定初始化函數(shù),那么便利初始化函數(shù)必須調(diào)用自己的其它初始化函數(shù)(包括指定初始化函數(shù)以及其他的便利初始化函數(shù)),不能調(diào)用super的初始化函數(shù)。
16.實現(xiàn)description方法能取到效果?
description是NSObject的實例方法,返回值是一個NSString,我們使用NSLog打印結(jié)果的時候,打印的對象一般都是內(nèi)存地址,我們實現(xiàn)description方法時,就可以打印出對象,我們可以把屬性值和內(nèi)存地址一起打印出來。
-(NSString *)description{
NSString * string = [NSString stringWithFormat:@"<Person:內(nèi)存地址:%p name = %@ age = %ld>",self,self.name,self.age];
return string;
}
17.objc使用什么機制管理對象內(nèi)存?
OC使用內(nèi)存管理計數(shù)器來管理內(nèi)存,當內(nèi)存管理計數(shù)器為0的時候,對象就會被釋放。
18.block實質(zhì)是什么?一共有幾中block?都是在什么情況下生成?
1.block的本質(zhì)就是object-c對象
2.block存儲位置:分為三個地方,代碼區(qū),堆區(qū),棧區(qū)(ARC的情況下會自動拷貝到堆區(qū),因此ARC情況下只能去兩個地方,代碼區(qū)和堆區(qū))
2.1.代碼區(qū):不能訪問棧區(qū)變量(比如局部變量)也不能訪問堆區(qū)變量(alloc創(chuàng)建的對象),此時block存放在代碼區(qū)
2.2.堆區(qū):訪問處于棧區(qū)或者堆區(qū)的變量,block存放在堆區(qū),需要注意的是,實際存放的是棧區(qū),不過ARC狀態(tài)下會自動拷貝到堆區(qū),如果不是ARC就是存放在棧區(qū),所以函數(shù)執(zhí)行完畢就會被釋放,想在外面調(diào)用就是用copy,就拷貝到了堆區(qū),strong屬性不會拷貝,會造成野指針錯區(qū)。
19.為什么在默認情況下無法修改block捕獲的變量,__block都做了什么??
1.默認情況下,block里面的變量,拷貝進去的是變量的值,而不是指向變量內(nèi)存的指針
2.當使用__block修飾變量,拷貝到block里面就是指向變量的指針,就可以修改變量的值
20.object在向一個對象發(fā)送消息時,發(fā)生了什么?
根據(jù)對象的isa指針類對象的id,在查詢類對象里面的methodLists方法函數(shù)列表,如果沒有找到,再沿著superClass尋找父類,再在父類methodLists方法列表里面查詢,最終找到SEL,根據(jù)id和SEL確認IMP(指針函數(shù)),然后發(fā)送消息。
21.什么時候會報unrecognized selector錯誤?iOS有哪些機制避免走到這一步?
當我們發(fā)送消息的時候,我們會根據(jù)類里面的methodLists方法列表查詢我們要動用SEL,當查詢不到的時候,我們會沿著父類查詢,當最終查詢不到的時候會報unrecognized selector錯誤,當系統(tǒng)查不到的時候會調(diào)用 +(BOOL)resolveInstanceMethod:(SEL)sel 方法,動態(tài)解釋的方法再添加吊用不到的方法,或者我們可以再次使用 -(id)forwardingTargetForSelector:(SEL)aSelector 重定向方法告訴系統(tǒng),該調(diào)用什么方法,保證不會崩潰。
22.能否向編譯后的類中增加實例變量?能否向運行時創(chuàng)建的類中增加實例變量?為什么??
1.不能向編譯后得到的類中增加實例變量。編譯后的類中已經(jīng)注冊在runtime中,類結(jié)構(gòu)體中的objc_ivar_list(屬性列表)實例變量的鏈表和instance_size(實例變量的內(nèi)存大?。嵗兞康膬?nèi)存大小已經(jīng)確定,runtime會調(diào)用class_setvarlayout或calss_setWeaklvarLayout來處理strong weak引用,所以不能向存在的類中增加實例變量
2.能向運行時創(chuàng)建的類中增加實例變量。運行時創(chuàng)建的類中是可以添加實例變量的,調(diào)用class_addlvar函數(shù),但是在調(diào)用objc_allocClassPair之后,調(diào)用objc_registerClassPair之前
23.runtime如何實現(xiàn)weak變量的自動置nil?
runtime會對類的注冊進行布局,對于weak對象會放入一個hash表中,使用weak指向的對象內(nèi)存地址為key,當這個對象引用計數(shù)為0的時候會dealloc,假如weak指向的對象內(nèi)存地址是a,那么就會以a為鍵,在這個weak表中搜索,找到所有以a為鍵值的weak對象,從而設(shè)置為nil。
24.給類增加屬性之后,在類的結(jié)構(gòu)體哪些元素會發(fā)生變化??
1.instance_size :實例的內(nèi)存大小
2.objc_ivar_list *ivars:屬性列表
25.runloop是做什么的?runloop和線程有什么關(guān)系?主線程默認開啟了runloop嗎?子線程呢?
1.runloop使用來處理線程里面的事件和消息
2.runloop和線程的關(guān)系:每個線程如果想繼續(xù)運行,不被釋放,就必須有一個runloop不停地調(diào)用,用來處理線程里面的各個事件和消息。
3.主線程默認開啟runloop,也就是這個runloop才能保證我們的程序正常運行,子線程是默認沒有開啟runloop.
26.runloop的mode是做什么的?有幾種model?
系統(tǒng)默認注冊了5個model:
1. kCFRunLoopDefaultMode:這是App默認的Model,通常主線程就是在這個Model下運行的。
2. UITrackingRunLoopMode:這個是界面跟蹤的Model,用于ScrollView追蹤觸摸滑動,保證界面滑動時不受其他Model影響。
3. UIInitializationRunLoopMode:這個是剛啟動App時進入的第一個Model,啟動完成就不再使用。
4. GSEventReceiveRunLoopMode:這個接受系統(tǒng)事件內(nèi)部的Model,沒什么實際作用。
5.kCFRunLoopCommonModes: 這是一個占位的 Mode,沒有實際作用。
注意:iOS對以上五中model進行了封裝,NSDefaultRunLoopMode,NSRunLoopCommonModes
27.為什么把NSTime對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環(huán)后,滑動ScrollView的時候NSTime卻不動了。
NSTime對象是在NSDefaultRunLoopMode下面調(diào)用消息的,但是當我們滑動scrollView的時候,NSDefaultRunLoopMode模式就自動切換到UITrackingRunLoopMode模式下面,不可以繼續(xù)響應(yīng)NSTime發(fā)送的消息,如果想在滑動scrollView的情況下還能調(diào)用NSTime的消息,我們可以把NSrunloop的模式更改為NSRunLoopCommonModes。
28.蘋果是如何實現(xiàn)Autorelease Pool的?
Autorelease Pool作用:緩存池,避免我們經(jīng)常寫relase的一種方式,其實就是延遲relase,將創(chuàng)建的對象添加到autorelease Pool中,等到autorelease Pool作用于結(jié)束,會將所有的對象的引用計數(shù)器-1
28.類結(jié)構(gòu)中isa指針(對象的isa,類對象的isa,元類的isa都要說)
在oc中,類也是對象,屬于元類
1.對象的isa指針指向所屬的類
2.類的isa指針指向了所屬的元類
3.元類的isa指針指向了根元類,根元類指向了自己
29.類的方法和實例方法有什么區(qū)別
1.調(diào)用的方式不同,類的方法必須使用類調(diào)用,在方法里面不能調(diào)用屬性,類方法里面也必須調(diào)用類方法,存儲在元類結(jié)構(gòu)體的methodLists里面
2.實例方法必須使用實例對象調(diào)用,可以在實例方法里面使用屬性,實例方法也必須調(diào)用實例對象,存儲在類結(jié)構(gòu)體的methodLists里面
30.分類你那個做什么?內(nèi)部怎么實現(xiàn)?會什么會覆蓋原來的方法?
category:我們可以給類或者系統(tǒng)類添加實例方法。我們添加的方法會被動態(tài)添加到類結(jié)構(gòu)里面的methodsList方法列表里面,
category的方法被放到了新方法列表的前面,而原來類的方法被放到了新方法列表的后面,這也就是我們平常所說的category的方法會“覆蓋”掉原來類的同名方法,這是因為運行時在查找方法的時候是順著方法列表的順序查找的,它只要一找到對應(yīng)名字的方法,就會罷休^_^,殊不知后面可能還有一樣名字的方法。
31.運行時能增加成員變量嗎?能增加屬性嗎?如果能,怎么增加,為什么?
運行時可以添加屬性,但是必須實現(xiàn)它的getter和setter方法,但是不能添加帶下劃線的成員變量,可以通過runtime添加。
32.objc向一個nil對象發(fā)送消息會發(fā)生什么?
1.如果一個方法返回值是一個對象,那么發(fā)送給nil的消息將返回0(nil),
例如:Person * motherInlaw = [ aPerson spouse] mother];
如果spouse對象為nil,那么發(fā)送給nil的消息mother也將返回nil。
2.如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*),float,double,long double 或者long long的整型標量,發(fā)送給nil的消息將返回0。
3.如果方法返回值為結(jié)構(gòu)體,正如在《Mac OS X ABI 函數(shù)調(diào)用指南》,發(fā)送給nil的消息將返回0。結(jié)構(gòu)體中各個字段的值將都是0。其他的結(jié)構(gòu)體數(shù)據(jù)類型將不是用0填充的。
4.如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的。
33.UITableview的優(yōu)化方法(緩存高度,異步繪制,減少層級,hide,避免離屏渲染)
緩存高度:當我們創(chuàng)建的時候frame模型的時候,計算出來cell的高度,我們可以將cell的高度緩存到字典里面,以cell的indexpath和Identifier作為key。
hide:個人理解應(yīng)該是hidden吧,把可能會用到的控件都創(chuàng)建出來,根據(jù)不同的情況去隱藏或者顯示出來。
避免離屏渲染:只要不是同時使用邊框/邊框顏色以及圓角的時候,都可以使用layer直接設(shè)置。不會造成離屏渲染。