前言
學如逆水行舟,不進則退。共勉??!
前段時間在金九銀十的跳槽季節(jié)里,我也是經(jīng)過自己的思考,面試了幾家我覺得挺不錯的公司。我也是成功靠岸了。我給大家分享一下我面試刷的一份面試題吧,給我提供了很大的幫助。優(yōu)秀的人可以點點關(guān)注,點點贊。
如需更多iOS資料可關(guān)注主頁,加入圈子
一C語言相關(guān)面試題
1.static有什么用途?
答案:在C語言中,static主要定義全局靜態(tài)變量,定義局部靜態(tài)變量,定義靜態(tài)函數(shù)。
static 屬于靜態(tài)變量,使用它修飾的變量生命周期是整個源程序。
@1.在函數(shù)體內(nèi)的 static 變量的作用范圍為該函數(shù)體,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時仍維持上次的值;
@2.在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所有函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;
@3.在模塊內(nèi)的 static 函數(shù)只被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明它的模塊內(nèi);
2.說下冒泡排序的原理?
答案:1.兩兩比較,質(zhì)量大的下沉,質(zhì)量小的上?。?2.外層循環(huán)用于控制排序次數(shù),n個數(shù)需要n-1次; 3.內(nèi)層循環(huán)用于兩兩比較,每次找出最大的沉到最底部;
for(i=1; i<n; i++)
{
for(j=0; j<n-i; j++){
if(ary[j] > ary[j+1]){
temp = ary[j];
ary[j] = ary[j+1];
ary[j+1] = temp;
}
}
}
3.說下選擇排序的原理?
答案:1.每次獲取一個關(guān)鍵字與它后面的數(shù)進行一一比較,找出最小的數(shù)與關(guān)鍵字進行交換; 2.外層循環(huán)用于獲取關(guān)鍵字,同時控制循環(huán)次數(shù)(n個數(shù)需要n-1次); 3.內(nèi)層循環(huán)用于將關(guān)鍵字與它后面的數(shù)一一比較,找出最小的數(shù)與關(guān)鍵字進行交換;
for(i=0; i<n-1; i++){
for(j=i+1; j<n; j++){
if(ary[i] > ary[j]){-->這里ary[i]就是關(guān)鍵字
temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
}
}
}
第一趟選擇排序:從n個數(shù)中找出最小的數(shù),將它與第一個數(shù)(即關(guān)鍵字)交換,結(jié)果最小的數(shù)被安置在第一個元素位置上;
第二趟選擇排序:從n-1個數(shù)中找出次小的數(shù),將它與第二個數(shù)(即關(guān)鍵字)交換,結(jié)果次小的數(shù)被安置在第二個元素位置上;
重復上述過程,共經(jīng)過n-1趟排序后,排序結(jié)束。
4.說下二分查找的原理和先決條件?
答案:1.先決條件:必須是一維順序數(shù)組;
2.原理:取中,比較;
3.設(shè)置最小索引和最大索引,定一個while循環(huán)語句條件是最小索引<最大索引,首先判斷要查找的值等不等于這2個索引對應的值,等于就查找成功了。不等于再定義一個中間索引,判斷要查找的值等不等于中間索引對應的值,等于就查找成功了。不等于那就判斷要查找的值是否小于中間索引對應的值,小于的話就把中間索引減1賦值給最大索引,反之就把中間索引加1賦值給最小索引。
設(shè)置數(shù)組r最小索引low,最大索引high,求數(shù)組的中間索引mid=(low+high)/2; //設(shè)置數(shù)組的最大和最小索引,求數(shù)組的中間索引
若r[mid]==k,查找成功; //若中間索引的值等于要查找的數(shù),則查找成功
若r[mid]>k,設(shè)置high=mid-1,繼續(xù)進行二分查找; //若中間索引的值大于要查找的數(shù),設(shè)置最大索引為中間索引減1,繼續(xù)進行二分查找
若r[mid]<k,設(shè)置low=mid+1,繼續(xù)進行二分查找。 //若中間索引的值小于要查找的數(shù),設(shè)置最小索引為中間索引加1,繼續(xù)進行二分查找
5.說下你對C語言指針的理解?
答案:1.指針就是內(nèi)存的地址,是C語言中廣泛使用的一種數(shù)據(jù)類型。運用指針編程是C語言最主要的風格之一。 2.C語言允許用一個變量來存放指針,這種變量稱為指針變量。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu);能很方便地使用數(shù)組和字符串;從而編出精煉而高效的程序。
6.C語言里的順序鏈表如何實現(xiàn)呢?
答案:定義幾個結(jié)構(gòu)體,每個結(jié)構(gòu)體里面包含倆個成員,一個整形變量,一個指針變量。讓一個結(jié)構(gòu)體里的指針變量指向另一個結(jié)構(gòu)體的地址,而另一個結(jié)構(gòu)體里的指針變量又指向另一個結(jié)構(gòu)體的地址。從而形成一個順序鏈表。
7.C語言里的循環(huán)鏈表如何實現(xiàn)呢?
答案:定義幾個結(jié)構(gòu)體,每個結(jié)構(gòu)體里面包含倆個成員,一個整形變量,一個指針變量。讓一個結(jié)構(gòu)體里的指針變量指向另一個結(jié)構(gòu)體的地址,而另一個結(jié)構(gòu)體里的指針變量又指向另一個結(jié)構(gòu)體地址。然后讓最后一個結(jié)構(gòu)體里的指針變量指向開始那個結(jié)構(gòu)體的地址,從而形成一個循環(huán)鏈表。
8.說下你對C語言二叉樹的了解
答案:在計算機科學中,二叉樹是每個節(jié)點最多有兩個子樹的樹結(jié)構(gòu)。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹常被用于實現(xiàn)二叉查找樹和二叉堆。
9.C語言里typedef與define有什么區(qū)別呢?
答案:#define 是在預編譯時處理的,它只能作簡單的字符串替換。 typedef 是在編譯時處理的,它是給已有類型起別名。
10.寫一個標準宏MIN,這個宏輸入兩個參數(shù)并返回較小的一個?
答案:#define MIN(X,Y) ((X)>(Y)?(Y):(X)) define只會是純替換作用,所以X,Y均需要加括號,以防止X,Y為表達式的情況
三目條件運算符,語法格式;x?y:z; 其中x為bool類型表達式,先計算x的值,若為true則結(jié)果為表達式y(tǒng)的值,否則結(jié)果為表達式z的值。
二.內(nèi)存管理面試題6個
1.說下你對內(nèi)存管理的理解?
答案:1.在非ARC的情況下,誰創(chuàng)建誰釋放,當對對象進行alloc,new,retain,copy時,需要調(diào)用release或autorelease釋放。當引用計數(shù)為0的時候,會調(diào)用dealloc方法銷毀當前對象。
2.在ARC的情況下,任何強指針(strong,retain)指向的對象就會被銷毀;任何弱指針(assign)指向的對象就不會被銷毀;默認情況下對象都是強指針類型。
3.自動釋放池是OC的一種內(nèi)存自動回收機制,可以將一些臨時變量通過自動釋放池來回收統(tǒng)一釋放;內(nèi)存池autoreleasepool是用于管理那些被聲明為autorelease的對象,系統(tǒng)中有成千上萬個內(nèi)存池,系統(tǒng)內(nèi)存不足時,系統(tǒng)會從棧中取最頂層的池子把引用計數(shù)為0的對象釋放掉,收回的內(nèi)存給當前應用程序使用。
自動釋放池本身銷毀的時候,池子里面所有的對象都會做一次release操作。
在使用block的時候,一定要注意不能在block里面直接對對象進行操作,而是要是要使用__block或__weak進行修飾,避免循環(huán)引用,造成內(nèi)存泄漏。
2.ARC環(huán)境下有內(nèi)存泄漏嗎?如果有,請舉例說明。
答案:有。比如:兩個用strong修飾的對象相互引用或 某個控制器里有循環(huán)引用都會導致內(nèi)存泄漏。
3.說下深拷貝與淺拷貝的區(qū)別?
答案:淺拷貝指的是只復制對象的指針,而不會復制對象的屬性的地址。 深拷貝指的是即會復制對象的指針也會復制對象的屬性的地址。
4.什么是自動釋放池?它的底層是怎么實現(xiàn)的?
答案:1.自動釋放池是OC的一種內(nèi)存自動回收機制。當對象調(diào)用autorelease時,該對象就會被放入到自動釋放池中。當自動釋放池被回收時,就會從棧中刪除,并且會給池子里面的所有對象都會做一次release操作。
答案:自動釋放池是OC的一種內(nèi)存自動回收機制,可以將一些臨時變量通過自動釋放池來回收統(tǒng)一釋放;
內(nèi)存池autoreleasepool是用于管理那些被聲明為autorelease的對象,系統(tǒng)中有成千上萬個內(nèi)存池,系統(tǒng)內(nèi)存不足時,系統(tǒng)會從棧中取最頂層的池子把引用計數(shù)為0的對象釋放掉,收回的內(nèi)存給當前應用程序使用。
自動釋放池本身銷毀的時候,池子里面所有的對象都會做一次release操作。
5.程序出現(xiàn)內(nèi)存泄漏,該如何解決?
答案: 1.單步斷點調(diào)試,找出內(nèi)存泄漏的地方,
2.使用全局斷點,鎖定程序閃退的地方,找出內(nèi)存泄漏的原因
3.使用僵尸變量,根據(jù)打印日志,然后分析原因,找出內(nèi)存泄漏的地方
4.分段調(diào)試,找出內(nèi)存泄漏的地方
5.使用Instrument當中的Leak檢測工具
6.實際開發(fā)中,如何對內(nèi)存進行優(yōu)化呢?
答案:1.用ARC管理內(nèi)存,它能保證釋放掉不再需要的對象內(nèi)存
2.盡量把VIew設(shè)置成透明
3.避免反復處理數(shù)據(jù)
4.優(yōu)化tableVIew
5.當對視圖控制器進行pop或dismiss操作的時候,把該視圖控制器的視圖對象等于nil或者直接remove掉。
6.在使用block的時候,一定要注意不能在block里面直接對對象進行操作,而是要是要使用__block或__weak進行修飾,避免循環(huán)引用,造成內(nèi)存泄漏。
- 使用Instrument當中的Leak檢測工具
- 使用Autorelease Pool
三.Objective-C語言相關(guān)面試題16個
1.描述一下你對OC堆和棧的理解?
答案:堆由開發(fā)人員控制,比如:alloc的對象,要手工釋放或交由系統(tǒng)釋放; 棧是由編譯器自動管理,無需我們手動控制。
2.什么是單例呢?
答案:單例模式的意思就是只有一個實例對象。而且自行實例化并向整個系統(tǒng)提供這個實例。
答案:單例就是使得一個類的對象成為系統(tǒng)中唯一的實例對象,需要用static創(chuàng)建這個全局對象。
3.ARC環(huán)境下創(chuàng)建單例有哪兩種方式,請舉例說明?
答案:1.創(chuàng)建一個全局靜態(tài)實例并設(shè)置成nil;實現(xiàn)一個實例構(gòu)造方法并進行同步處理,再判斷上面聲明的靜態(tài)實例是否為nil,如果是則新建并返回這個實例對象; 2.使用GCD線程中的只執(zhí)行一次的方法來創(chuàng)建單例。
4.MRC下怎么創(chuàng)建單例模式呢?
答案:必須重寫allocWithZone,copyWithZone,release和autorelease方法,用來保證其他人直接使用alloc和init試圖獲得一個新實例時不產(chǎn)生新實例。
5.說下KVC與KVO的區(qū)別?
答案:1.KVC是鍵值編碼,即通過字符串的名字(key)來訪問類屬性。而不是通過調(diào)用Setter、Getter方法來訪問。即使這個屬性它沒有Set和Get方法,我們也能訪問;注意:當這個屬性有Set方法系統(tǒng)會優(yōu)先調(diào)用Set方法,通過KVC設(shè)值對象,此對象會被retain。
2.KVO是鍵值監(jiān)聽,即指定觀察的對象屬性被修改后,KVO就會自動通知相應的觀察者,用完后需要在dealloc方法中移除觀察者。如果開啟了ARC機制后也可以調(diào)用dealloc方法,只不過不能調(diào)用[super dealloc],然后在dealloc方法中移除觀察者。
6.描述下synthesize與dynamic的作用?
答案:1.@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。如果@synthesize和@dynamic都沒寫,那么默認的就是@syntheszie var = _var;
2.@synthesize的語義是如果你沒有手動實現(xiàn)setter方法和getter方法,那么編譯器會自動為你加上這兩個方法。
3.@dynamic告訴編譯器,屬性的setter與getter方法由用戶自己實現(xiàn),不自動生成。(當然對于readonly的屬性只需提供getter即可)。假如一個屬性被聲明為@dynamic var,然后你沒有提供@setter方法和@getter方法,編譯的時候沒問題,但是當程序運行到instance.var =someVar,由于缺setter方法會導致程序崩潰;或者當運行到 someVar = var時,由于缺getter方法同樣會導致崩潰。編譯時沒問題,運行時才執(zhí)行相應的方法,這就是所謂的動態(tài)綁定。
7.類與類之間的消息傳遞,有哪幾種方式呢?
答案:委托代理delegate,消息通知,KVO鍵值監(jiān)聽,block塊。
8.描述下你對消息通知的理解?
答案:通知(NSNotificationCenter)是一對多的關(guān)系,當一個類需要跟多個類進行信息傳遞的時候,我們一般都是用消息通知,
①通知時同步的,使用時必須先注冊并綁定接收通知的方法,
②消息中心創(chuàng)建消息內(nèi)容,然后發(fā)送通知
③不在監(jiān)聽時調(diào)用dealloc方法移除通知對象!
答案:用于通知多個對象某個事件,在對象中實現(xiàn)對象監(jiān)聽及監(jiān)聽的方法;是一對多的模式,只要接收通知都能響應方法。
9.主線程注冊通知事件,子線程發(fā)通知事件,那響應方法在哪個線程完成呢?
答案:子線程完成,在哪個線程發(fā)送通知就在哪個線程響應
10.描述一下你對委托代理的理解,它支持一對多嗎?如果支持,如何實現(xiàn)?
答案:委托代理是類與類之間信息傳遞的一種方式,使用委托代理的時候,必須先聲明協(xié)議,確認協(xié)議并實現(xiàn)協(xié)議中聲明的方法,添加要委托的對象,最后才能使用,
它支持一對多嗎?:可以!即可以把委托delegate改成數(shù)組保存多個委托對象,調(diào)用時取出每一個委托對象進行信息傳遞。
答案:委托代理是類與類之間信息傳遞的一種方式,協(xié)議只聲明了方法,不具體實現(xiàn),接受協(xié)議的對象負責實現(xiàn);
11.什么是類別?什么是延展?詳細描述一下你的理解
答案:類別是給已有類添加新的方法且對外界公開,不能添加實例變量; 延展是給類添加私有變量,屬性及方法。對外界不公開。
12.詳細描述一下你對block的理解,它的作用有哪些呢?
答案:block 是IOS4.0之后新增一種語法結(jié)構(gòu),也稱閉包
SDK4.0,新增的API大量使用了block
block類似一個匿名的函數(shù)代碼塊,此代碼塊可以作為參數(shù)傳遞對象或方法,也可以作為方法的返回值;
block可以實現(xiàn)兩個類之間的信息傳遞,
并且block對局部變量是只讀的,如果要修改可以加__block進行修飾。
block是獲取其他函數(shù)局部變量的匿名函數(shù)功能是保存代碼片段, 預先準備好代碼, 并在需要的時候執(zhí)行.
作用:在兩個類之間的信息傳遞 或者對代碼封裝作為參數(shù)進行傳遞 或者作為方法的返回值 利用block實現(xiàn)代理委托delegate
13.ARC環(huán)境下使用block會產(chǎn)生內(nèi)存泄漏嗎?如果會,該如何解決呢?
答案:當在block里面直接調(diào)用局部對象或者當前對象self的屬性或方法的時候,局部對像或當前對象,就會block隱性的retain一次,導致相互引用,內(nèi)存泄漏!
可以加__block,或使用完之后立即釋放block,防止內(nèi)存泄漏
1.使用__block修飾當前對象 2.block使用完后立即釋放,即self.block=nil
14.類別和繼承有什么區(qū)別呢?
答案:類別:是給已有的類添加新的方法,向?qū)ο筇砑臃钦絽f(xié)議 ,使原有類的功能更加強大,但是不能添加實例變量!
繼承:子類繼承父類,子類就擁有了父類的成員、屬性及方法,這樣可以節(jié)省代碼量,使程序更加簡潔,也可以添加新的屬性及方法,使功能更加強大!
成員也可以使用權(quán)限控制,@private私有的,@protected受保護的,@public公共的
答案:繼承修改的方法不會對父類原方法產(chǎn)生影響; 類別修改的方法相當于替換了原有方法。
15.NSPredicate即謂詞邏輯,可以用來做什么呢?
答案:redicate即謂詞邏輯,用于從數(shù)據(jù)堆中根據(jù)條件進行篩選,大多用于數(shù)組對象的篩選。 (1). 可用于數(shù)組中數(shù)字對象和字符串對象的比較; (2). 可用于篩選符合條件的數(shù)組元素;
16.描述下__block和__weak修飾符的區(qū)別?
答案:__block不管在ARC模式下還是MRC模式下,都可以使用,可以修飾對象,還可以修飾修飾基本數(shù)據(jù)類型 __weak只能在ARC的模式下使用,只能修飾對象,不能修飾基本的數(shù)據(jù)類型 __block對像可以在block中重新被賦值,__weak不可以
四.UI界面相關(guān)9個題
1.什么是MVC模式?什么是MVVM模式?詳細說明一下。
答案:MVC模式
Model是數(shù)據(jù)層;View是用于顯示界面;Controller將model和view綁定在一起,也是model和view通信的橋梁。
MVVM框架與傳統(tǒng)的MVC框架極為相似,是MVC框架的延伸。
M:即Model層,數(shù)據(jù)模型,用來定制數(shù)據(jù)的。 創(chuàng)建的實體類都是放在這個文件夾里;
V: 即ViewController層,即視圖控制器。 用來顯示界面以及與用戶交互;
它又可以細分成View層和Controller層,其中View層保存純視圖類,Controller層保存控制器;
VM: 即ViewModel層,即業(yè)務(wù)邏輯層。用來處理ViewController層的業(yè)務(wù)邏輯和界面邏輯, 比如:網(wǎng)絡(luò)數(shù)據(jù)請求,
json解析,本地數(shù)據(jù)存儲,用戶登錄密碼校驗,圖片上傳與下載等。說明了,就是把原來的ViewContrller
層的業(yè)務(wù)邏輯和頁面邏輯等剝離出來放到ViewModel層。
2.描述一下UITableView的重用機制?
答案:tableview有個可重用隊列,滑出去的會放到可重用隊列里面,滑進來的會從可重用隊列里面獲取,如果沒有,會創(chuàng)建一個cell,cell的可重用標示是用static靜態(tài)變量聲明的。
3.如果想讓scrollview實現(xiàn)重用,有什么好的思路呢?
答案:可以把UITableView逆時針轉(zhuǎn)90度,tableview里的cell順時針轉(zhuǎn)90度,使用它們的屬性transform來實現(xiàn)。同時修改tableview的frame以及當前的cell的高度,即可實現(xiàn)。
4.視圖控制器從創(chuàng)建到銷毀分別經(jīng)歷哪些方法呢?
答案:alloc—init—loadview(創(chuàng)建并加載一個屬于自己的根視圖)—viewdidload(視圖加載完成)—viewwillappear(視圖將要顯示)—viewdidappear(視圖已經(jīng)顯示)—viewWillDisapper(視圖將要消失)—viewDiddisappear(視圖已經(jīng)消失)—dealloc
5.描述一下事件的響應者鏈。
答案:當前觸發(fā)事件--根視圖上的子視圖--視圖控制器上的根視圖--視圖控制器--窗口--UIApplication對象--丟棄
6.didMoveToSuperView,layoutSubviews,drawRect都在什么時候調(diào)用呢?實際編碼中用來做什么呢?
答案:didMoveToSuperView:當繼承自UIView的子視圖被貼到父視圖時調(diào)用,可以在此方法中設(shè)置子視圖自身的屬性;
layoutsubviews:當添加到父視圖或自己添加子視圖時調(diào)用,當修改自己的frame或子視圖的frame時也會調(diào)用,當自己調(diào)用setNeedsLayout方法時也會調(diào)用,父視圖UIScrollView滾動時或屏幕旋轉(zhuǎn)時也會調(diào)用(待求證)??梢栽诖朔椒▽ψ右晥D進行重新布局;
drawRect:貼到父視圖的時候調(diào)用,設(shè)置它的contentMode屬性值為UIViewContentModeRedraw時,每次更改frame的時候調(diào)用,直接調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:方法的時候調(diào)用??梢栽诖朔椒ㄖ欣L制自己的內(nèi)容。
7.CALayer和UIView的區(qū)別是什么呢?
答案:兩者最大的區(qū)別是:圖層不會直接渲染到屏幕上,UIView是IOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自它。它本身完全由CoreAnimation 來實現(xiàn)的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器。一個UIView上可以有n個CALayer,每個layer顯示一種東西,增強UIView的展現(xiàn)能力。
8.UIScrollview如何做垂直方向的約束呢?
答案:storyboard里設(shè)置scrollview的小技巧:
(1).首先托一個scrollview到故事板里(可以全屏也可以任意大小),給scrollview添加左,右,上,下四個約束;
(2).然后在scrollview上托一個UIView,大小與scrollview一樣大,給UIView添加左,右,上,下,固定高,垂直居中對齊幾個約束;(固定高,垂直居中對齊兩個約束一定要加,否則滾動失效??!)
(3).以后所有的子控件都可以放到這個UIView上顯示了;
9.說一下UIScrollerView實現(xiàn)原理。
答案:在滾動過程當中,其實是在修改原點坐標。當手指觸摸后, scrollview會暫時攔截觸摸事件,使用一個計時器。假如在計時器到點后沒有發(fā)生手指移動事件,那么 scrollview 發(fā)送 tracking events 到被點擊的 subview。假如在計時器到點前發(fā)生了移動事件,那么 scrollview 取消 tracking 自己發(fā)生滾動。
五.多線程相關(guān)面試題8個
1.描述一下線程與進程的區(qū)別?
答案:1.進程有獨立的地址空間,一個進程崩潰后,在其保護模式下不會對其他進程產(chǎn)生影響,而線程只是一個進程中的執(zhí)行路徑。
2.線程有自己的堆棧,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程程序比多線程程序健壯。
3.但在進程切換時耗費資源較大,效率要差一些。對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程不能用進程。
2.你所掌握的多線程有哪些呢?它們的特點是什么?
答案:NSThread:NSThread是輕量級的,需要自己管理線程的生命周期,線程同步。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷;
Cocoa operation:Cocoa operation不需要關(guān)心線程管理,數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上。相關(guān)的類是NSOperation,NSOpertionQueue.它是一個抽象類,使用時必須用它的子類NSInvocationOpertion.創(chuàng)建子類的對象并把它添加到NSOperationQueue隊列里執(zhí)行。
GCD:是Apple開發(fā)的一個多核編程的解決方法,是一個替代諸如NSThread,NSOperationQueue,NSInvocationOperation等高效.強大的技術(shù);GCD本身非常簡單,易用,對于不復雜的多線程操作,會節(jié)省代碼量,而block參數(shù)的使用,會使代碼更為易讀。
3.描述一下線程同步與異步的區(qū)別?
答案: 線程同步是指當前有多個線程的話,必須等一個線程執(zhí)行完了才能執(zhí)行下一個線程。使用加鎖處理。線程異步就不需要等待了,可以同時進行。
答案:線程同步指一個線程要等待上一個線程執(zhí)行完之后才開始執(zhí)行下一個線程;
線程異步指一個線程去執(zhí)行,他的下一個線程不用等待他執(zhí)行完就開始執(zhí)行。
同步需要用@synchronized 或加鎖解鎖處理
異步主要使效率提高
同步線程主要解決線程安全問題,異步主要使效率提高
4.多線程在實際代碼中有哪些應用場景呢?
答案: 當我們進行網(wǎng)絡(luò)請求的時候,網(wǎng)絡(luò)請求就使用了多線程處理, 當我們進行JSON解析的時候,也使用了多線程進行處理, 當我們進行本地緩存的時候,也會使用多線程進行處理,主線程用于界面刷新,子線程用于數(shù)據(jù)處理。
5.使用GCD加載多張圖片之后,如何把加載的圖片融合到一張圖片里呢?
答案: 在GCD線程里創(chuàng)建一個組,在組里添加幾個異步線程加載圖片,這些圖片加載完之后就匯總通知,然后調(diào)用主線程,在主線程里開啟圖形上下文,在drawinrect方法中繪制加載的圖片,獲取合成圖片,關(guān)閉圖形上下文,這就把加載的圖片融合到一張圖片里了。
6.使用GCD的時候,如何在一個group里添加幾個任務(wù)的依賴呢?
答案: 1、dispatch_group_async(group, queue, ^{ /* 任務(wù)A */ });
dispatch_group_async(group, queue, ^{ /* 任務(wù)B */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
dispatch_group_async(group, queue, ^{ /* 任務(wù)C */ });
dispatch_group_async(group, queue, ^{ /* 任務(wù)D */ });
});
創(chuàng)建一個組,然后在組里面添加異步線程,有幾個任務(wù)就添加幾次,當這些線程任務(wù)執(zhí)行完之后就匯總結(jié)果,然后再調(diào)用主線程刷新。
7.多線程共享同一數(shù)據(jù),如何防止錯亂呢?
答案:方法一:@synchronized(xin ke nai zi)會對參數(shù)對象同步處理,保證臨界區(qū)內(nèi)的代碼線程安全; 方法二:使用NSLock進行加鎖處理,等線程執(zhí)行結(jié)束再進行解鎖處理。
8.多線程之間如何進行數(shù)據(jù)傳遞的?應注意哪些事項。
答案: -(void) perfromSelectOnMainThread: withObject: waitUntilDone:
注意事項: waitUntilDone:是YES的話,子線程結(jié)束后會阻塞主線程,然后走要執(zhí)行的方法
如果是NO的話,就不會阻塞主線程,
或者使用:本地存儲的方式,或者使用block,使用block的時候需要用__block修飾
__block,
__weak,
子線程里嵌套主線程進行傳值;
子線程下載數(shù)據(jù)后直接丟給主線程刷新;
本地儲存;
注意的事項:多線程共享同一數(shù)據(jù),要防止錯亂。
六.本地存儲8個題
1.你所掌握的本地存儲有哪些呢,描述下它們各自的特點?
答案:文件寫入;歸檔;NSUserDefauls;FMDatabase(第三方數(shù)據(jù)庫),core data,系統(tǒng)數(shù)據(jù)庫sqlite
特點:
文件寫入:只能存儲系統(tǒng)的數(shù)據(jù)類型,永久保存在磁盤中;
歸檔(NSKeyedArchiver):采用歸檔的形式保存數(shù)據(jù),該數(shù)據(jù)對象需要遵守NSCoding協(xié)議,并且該對象對應的類必須提供2個方法,對象進行編碼的方法encodeWithCoder:,對象進行解碼的方法initWithCoder:然后創(chuàng)建沙盒,設(shè)置歸檔路徑,,使用NSKeyedArchiver序列化進行編碼,使用NSKeyedUnarchiver反序列化進行解碼。
NSUserDefaults:主要用來保存應用程序的設(shè)置和屬性,用戶再次打開程序或開機后這些數(shù)據(jù)仍然存在;
數(shù)據(jù)庫FMDB(FMDatabase第三方數(shù)據(jù)庫):FMDB是基于SQLite封裝過來的,它能很方便的對數(shù)據(jù)進行增刪改查。
CoreData:是一個模型層的技術(shù),也是一種持久化技術(shù),它能將模型對象的狀態(tài)持久化到磁盤里,它可以對數(shù)據(jù)進行增刪改查;
sqlite:是輕量級的嵌入式數(shù)據(jù)庫,系統(tǒng)中內(nèi)置了sqlite,它可以對數(shù)據(jù)進行增刪改查
2.如何對自定義的對象進行本地歸檔呢?
答案:采用歸檔的形式保存數(shù)據(jù),該數(shù)據(jù)對象需要遵守NSCoding協(xié)議,并且該對象對應的類必須提供2個方法,對象進行編碼的方法encodeWithCoder:,對象進行解碼的方法initWithCoder:。然后創(chuàng)建沙盒,設(shè)置歸檔路徑,使用NSKeyedArchiver序列化進行編碼,使用NSKeyedUnarchiver反序列化進行解碼。
3.說出數(shù)據(jù)庫中表的創(chuàng)建,以及對表進行增、刪、改、查的SQL語句。
答案:創(chuàng)建表:executeUpdate create table 表的名稱(表里面數(shù)據(jù)的類型)
增 :executeUpdate insert into 表的名稱(要增加的對象)
刪: executeUpdate delete from 表的名稱 where
改: executeUpdate update 表的名稱 set ……where ……
查: executeQuery select from 表的名稱 ,用while循環(huán)進行查詢。
4.詳細描述一下你對CoreData的理解?
答案:CoreData是一個模型層的技術(shù),也是一種持久化技術(shù),它能將模型對象的狀態(tài)持久化到磁盤里,它可以對數(shù)據(jù)進行增刪改查;
創(chuàng)建工程時,需要勾選CoreData選項,創(chuàng)建模型文件,可以在模型文件里進行添加實體對象;
然后新建一個NSManagedObject cubclass文件;
工程創(chuàng)建完之后,它會在AppDelegate.h里自動生成了3個屬性;
然后在需要使用的類里面添加CoreData頭文件,再使用它的屬性,就可以對數(shù)據(jù)進行增刪改查操作了;
5.詳細描述一下你對系統(tǒng)數(shù)據(jù)庫sqlite的理解?
答案:
sqlite是輕量級的嵌入式數(shù)據(jù)庫,系統(tǒng)中內(nèi)置了sqlite,現(xiàn)在的版本是sqilte3;
使用SQLite,只需要加入libsqlite3.0.tbd,以及引入sqlite3.h頭文件即可
然后就可以打開數(shù)據(jù)庫,
創(chuàng)建表,
執(zhí)行SQL語句,進行增刪改查等操作
然后關(guān)閉數(shù)據(jù)庫
6.如何對自定義的對象進行CoreData保存呢?
答案:①引入CoreData框架
②創(chuàng)建數(shù)據(jù)模型文件.xcdatamodel
③初始化NSManagedObjectModel對象,加載數(shù)據(jù)模型文件,讀取app中所有實體信息。
④初始化NSPersistentStoreCoordinator 對象,添加持久化庫
⑤初始化NSManagedObjectContext對象,拿到上下文對象操作實體。
7.CoreData是用什么篩選數(shù)據(jù)的?說出查詢age字段在18歲到28歲的篩選條件.
答案:
使用NSPredicate邏輯謂詞篩選,
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.age BETWEEN {18, 28}"];
或者
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.age >= 18 && SELF.age <=28"];
8.ios 10下集成coredata發(fā)生了哪些變化呢?
答案:IOS10中,系統(tǒng)默認只生成一個CoreData存儲容器;
創(chuàng)建CoreData時,先創(chuàng)建DataModel;
在創(chuàng)建好的數(shù)據(jù)模型里添加實體;
再創(chuàng)建NSManagedObject cubclass文件,它創(chuàng)建的地方不同,
然后在需要使用的類里面添加CoreData頭文件,再使用它的屬性,就可以對數(shù)據(jù)進行增刪改查操作了;
IOS9之前,數(shù)據(jù)是存儲在Documents 中;
ios10,數(shù)據(jù)庫文件存儲在Library->Application Support中。
七.網(wǎng)絡(luò)請求5個題
1.實際開發(fā)項目中,經(jīng)常用到的網(wǎng)絡(luò)請求有哪些呢?
答案:ASIHTTPRequest、AFNetWorking、NSURLConnection、NSURLSession(功能更強大,更穩(wěn)定);
AFNetWorking2.0和3.0的區(qū)別:底層封裝不同(3.0底層是封裝NSURLSession來實現(xiàn)的);
ios9以后,NSURLConnection被棄用;
2.詳細描述一下AFNetworking與ASIHttpRequest的區(qū)別?
問題:
1.底層實現(xiàn)不同,AFN的底層基于OC的NSURLConnection和NSURLSession;ASI的底層基于純C語言的CFNetwork框架;ASI的運行性能高于AFN。
2.對服務(wù)器返回的數(shù)據(jù)處理不同,ASI沒有直接提供對服務(wù)器數(shù)據(jù)處理的方式,直接返回data\string;AFN提供了多種對服務(wù)器數(shù)據(jù)處理的方式,JSON處理,XML處理
3.監(jiān)聽請求的過程不同 ,AFN只提供了成功和失敗兩個block來監(jiān)聽請求的過程 ,ASI提供了3套方案,每一套方案都能監(jiān)聽請求的完整過程
4.文件下載和文件上傳的使用難易度不同,afn不容易監(jiān)聽下載進度和上傳進度,不容易實現(xiàn)斷點續(xù)傳,而且一般只用來下載不大的文件,而asi則相反。
5.ASI提供了更多的實用功能,比如監(jiān)聽文件的上傳和下載過程,暫停/恢復/取消所有的網(wǎng)絡(luò)請求等;
答案:
1.底層實現(xiàn)
(1) AFN的底層基于OC的NSURLConnection和NSURLSession (2) ASI的底層基于純C語言的CFNetwork框架 (3) ASI的運行性能高于AFN2.對服務(wù)器返回的數(shù)據(jù)處理
(1) ASI沒有直接提供對服務(wù)器數(shù)據(jù)處理的方式,直接返回data\string (2) AFN提供了多種對服務(wù)器數(shù)據(jù)處理的方式 ? JSON處理 ? XML處理3.監(jiān)聽請求的過程
(1) AFN提供了success和failure兩個block來監(jiān)聽請求的過程(只能監(jiān)聽成功和失敗)
? success : 請求成功后調(diào)用
? failure : 請求失敗后調(diào)用
(2) ASI提供了3套方案,每一套方案都能監(jiān)聽請求的完整過程
(監(jiān)聽請求開始、接收到響應頭信息、接受到具體數(shù)據(jù)、接受完畢、請求失?。?br> ? 成為代理,遵守協(xié)議,實現(xiàn)協(xié)議中的代理方法
? 成為代理,不遵守協(xié)議,自定義代理方法
? 設(shè)置block4.在文件下載和文件上傳的使用難易度
(1) AFN ? 不容易監(jiān)聽下載進度和上傳進度 ? 不容易實現(xiàn)斷點續(xù)傳 ? 一般只用來下載不大的文件 (2) ASI ? 非常容易實現(xiàn)下載和上傳 ? 非常容易監(jiān)聽下載進度和上傳進度 ? 非常容易實現(xiàn)斷點續(xù)傳 ? 下載或大或小的文件都行5.ASI提供了更多的實用功能
(1) 控制圈圈要不要在請求過程中轉(zhuǎn)
(2) 可以輕松地設(shè)置請求之間的依賴:每一個請求都是一個NSOperation對象
(3) 可以統(tǒng)一管理所有請求(還專門提供了一個叫做ASINetworkQueue來管理所有的請求對象)
? 暫停\恢復\取消所有的請求
? 監(jiān)聽整個隊列中所有請求的下載進度和上傳進度
3.詳細描述一下你對get請求與post請求的理解?
答案:get是向服務(wù)器發(fā)送,索取數(shù)據(jù)的一種請求,get請求的參數(shù)會跟在url后進行傳遞,請求數(shù)據(jù)會附在url之后,以?分割url和傳輸數(shù)據(jù),參數(shù)之間以&相連;這樣的安全性不高,get請求的數(shù)據(jù)有大小限制,一般不超過255個字節(jié);
post是向服務(wù)器提交數(shù)據(jù)的,post請求會把消息放到消息體body里,安全性高且post沒有限制提交的數(shù)據(jù)。
4.實際開發(fā)中如何處理多個網(wǎng)絡(luò)請求的并發(fā)呢?
答案:可以使用GCD線程,創(chuàng)建一個組,然后在組里面添加異步線程,有幾個任務(wù)就添加幾次,當這些線程任務(wù)執(zhí)行完之后就匯總結(jié)果,然后再調(diào)用主線程刷新。
5.實際開發(fā)中AFNetworking發(fā)送出去的請求,如何主動取消呢?
答案:通過類別來動態(tài)管理請求隊列,避免VC直接持有請求隊列。 通過runtime來自動觸發(fā)取消請求操作。
八.自動布局4個題
1.如何讓一款應用兼容不同的屏幕,有哪幾種方案呢?
答案:有2種方式進行適配。
第一種是在實際代碼里寫一個宏判斷當前設(shè)備的高度,根據(jù)屏幕高度動態(tài)調(diào)整圖片及視圖的尺寸;
第二種是使用main.storboard里的屬性size class對不同屏幕尺寸進行分類處理,使用autolayout對不同屏幕下的尺寸進行自動布局,包括自動拉伸和自動貼邊。
第三種是使用masonry布局框架。
2.實際開發(fā)中添加約束時,如果產(chǎn)生了警告和沖突,該如何解決呢?
答案:一種是非運行時的約束沖突,在InterfaceBuilder里面就能看到的,比如同一個高度給了兩個約束,這兩個約束是無法同時滿足的,然后就沖突了,解決辦法就是去掉其中的一個約束;
另一種是在運行時的約束沖突,可以通過閱讀打印的日志,就能知道是哪里有沖突,解決辦法就是在運行的時候動態(tài)修改約束沖突。
3.描述一下你對masonry的理解?
答案:masonry是一個輕量級的布局框架,采用鏈式語法封裝自動布局,使程序代碼更為易讀,只聲明了方法,沒有聲明相應的屬性,通過添加約束條件來確定視圖的位置,而不是通過手動修改frame來進行布局,主要包含點語法、小括號調(diào)用、連續(xù)訪問 三部分
4.詳細描一下Xib與StoryBoard的區(qū)別?
答案:
Xib是輕量級的,用來描述局部的UI界面,一個工程中可以有多個xib文件,主要用于視圖,一個xib可以在不同的視圖控制器中使用。
storyboard是重量級的,用來描述整個軟件的多個界面,并且能展示多個界面之間的跳轉(zhuǎn)關(guān)系,主要用于視圖控制器。 然后多個storyboard之間可以關(guān)聯(lián)使用。
九.swift語言相關(guān)
1.詳細描述一下你對蘋果語言Swift的理解?
答案:swift是蘋果WWDC2014大會上發(fā)布的一種編程語言。它繼承了C語言以及Objective-C的特性,使用var命名變量,使用let命名常量,創(chuàng)建類時只有一個后綴為.swift的文件。支持playground,允許程序員寫一段swift代碼并立即看到結(jié)果。無需導入單獨的庫,無需編寫main()函數(shù),無需在每個語句后寫分號。
十.協(xié)議相關(guān)4個題
1.詳細描述一下對你TCP,UDP,HTTP的理解?
答案:HTTP協(xié)議,對應于應用層
TCP協(xié)議,對應于傳輸層;
UDP協(xié)議,對應于傳輸;
IP協(xié)議,對應于網(wǎng)絡(luò)層;
HTTP協(xié)議基于TCP連接的,TCP/IP是傳輸層協(xié)議,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸,而HTTP是應用層協(xié)議。
scoket是對TCP/IP協(xié)議的封裝,scoket本身并不是協(xié)議,而是一個調(diào)用接口(API),我們才能用TCP/IP協(xié)議。
2.詳細描述一下HTTP與HTTPS之間的區(qū)別?
答案:http是超文本傳輸協(xié)議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協(xié)議;
http的連接很簡單,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進行加密傳輸、身份認證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全;
如果使用http進行網(wǎng)絡(luò)請求時,需要在info.plist文件設(shè)置允許任意加載,禁用ATS。
https需要申請數(shù)據(jù)證書,公鑰,私鑰;
3.詳細描述下UDP和TCP的區(qū)別?
答案:TCP---傳輸控制協(xié)議,提供的是面向連接、可靠的字節(jié)流服務(wù)。當客戶和服務(wù)器彼此交換數(shù)據(jù)前,必須先在雙方之間建立一個TCP連接,之后才能傳輸數(shù)據(jù)。TCP提供超時重發(fā),丟棄重復數(shù)據(jù),檢驗數(shù)據(jù),流量控制等功能,保證數(shù)據(jù)能從一端傳到另一端。
UDP---用戶數(shù)據(jù)協(xié)議,是一個簡單的面向數(shù)據(jù)報的運輸層協(xié)議。UDP不提供可靠性,它只是把應用程序傳給IP層的數(shù)據(jù)報發(fā)送出去,但是并不能保證它們能到達目的地。由于UDP在傳輸數(shù)據(jù)報前不用在客戶和服務(wù)器之間建立一個連接,且沒有超時重發(fā)等機制,故而傳輸速度很快。
4.簡單描述一下TCP/IP建立連接通信的過程?
答案:在TCP/IP協(xié)議中,TCP協(xié)議提供可靠的連接服務(wù),采用三次握手建立一個連接。
第一次握手:建立連接時,客戶端發(fā)送連接請求到服務(wù)器,并進入SYN_SEND(發(fā)送)狀態(tài),等待服務(wù)器確認;
第二次握手:服務(wù)器收到客戶端連接請求,向客戶端發(fā)送允許連接應答,此時服務(wù)器進入SYN_RECV(接收)狀態(tài);
第三次握手:客戶端收到服務(wù)器的允許連接應答,向服務(wù)器發(fā)送確認,客戶端和服務(wù)器進入通信狀態(tài),完成三次握手。
十一.5個題
1.ios 10的新特性有哪些呢,舉例說明一下?
答案:它的語音識別api對外開放,提供了一套從語音識別到代碼處理,最后向用戶展示結(jié)果的流程;
它還封裝了新的通知中心,可以在推送通知中添加音頻,視頻,圖片等功能;
它還對外開放新的iMessage api,它可以對現(xiàn)有 App 延伸擴展,比如添加了貼紙表情包的功能,也可以發(fā)送圖片,鏈接,音頻,視頻內(nèi)容。
2.實際開發(fā)中,程序出現(xiàn)了閃退,該如何解決?
答案: 1.單步斷點調(diào)試,找出內(nèi)存泄漏的地方,
2.使用全局斷點,鎖定程序閃退的地方,找出內(nèi)存泄漏的原因
3.使用僵尸變量,根據(jù)打印日志,然后分析原因,找出內(nèi)存泄漏的地方
4.分段調(diào)試,找出內(nèi)存泄漏的地方
5.使用Instrument 當中的Leak檢測工具
3.詳細描述一下你對ATS的理解?
答案:一種網(wǎng)絡(luò)安全機制,這項機制確保 app 在進行網(wǎng)絡(luò)訪問時,使用業(yè)界標準的,沒有已知重大安全隱患的協(xié)議和加密方式,以此確保用戶的隱私和數(shù)據(jù)完整性。從而培養(yǎng)用戶對 app 的信任。
4.詳細描述一下你對ipv4與ipv6的理解。
答案:IP是TCP/IP協(xié)議族中網(wǎng)絡(luò)層的協(xié)議,是TCP/IP協(xié)議族的核心協(xié)議。目前IP協(xié)議的版本號是4(簡稱為IPv4)地址位數(shù)為32位。IPv6是下一版本的互聯(lián)網(wǎng)協(xié)議,IPv6采用128位地址長度,幾乎可以不受限制地提供地址。解決了地址短缺,有端到無端IP連接、服務(wù)質(zhì)量(QoS)、安全性、多播、移動性、即插即用等。IPv6與IPv4相比更大的地址空間。更小的路由表。
5.解決tableview滑動卡頓問題
之所以會造成這個問題,主要是因為cell賦值內(nèi)容時,會根據(jù)內(nèi)容設(shè)置布局,也就可以知道cell的高度,若有1000行,就會調(diào)用1000次 heightForRow方法,意味著每次回調(diào)這個方法時都要計算高度,而計算是要花時間了,在用戶體驗上的體現(xiàn)就是卡頓。
為了避免重復且無意義的計算cell高度,我們可以需要一個可變數(shù)組緩存高度,每當回調(diào)heightForRow這個方法時,我們先去這個數(shù)組里去取,如果有,就直接拿出來,如果沒有,就計算高度,并且放進數(shù)組,,這樣就可以解決卡頓問題。
十二、常問面試題
1.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述?
設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類型的事情。
1). MVC模式:Model View Control,把模型 視圖 控制器 層進行解耦合編寫。
2). MVVM模式:Model View ViewModel 把模型 視圖 業(yè)務(wù)邏輯 層進行解耦和編寫。
3). 單例模式:通過static關(guān)鍵詞,聲明全局變量。在整個進程運行期間只會被賦值一次。
4). 觀察者模式:KVO是典型的通知模式,觀察某個屬性的狀態(tài),狀態(tài)發(fā)生變化時通知觀察者。
5). 委托模式:代理+協(xié)議的組合。實現(xiàn)1對1的反向傳值操作。
6). 工廠模式:通過一個類方法,批量的根據(jù)已有模板生產(chǎn)對象。
2.MVC 和 MVVM 的區(qū)別
1). MVVM是對胖模型進行的拆分,其本質(zhì)是給控制器減負,將一些弱業(yè)務(wù)邏輯放到VM中去處理。 2). MVC是一切設(shè)計的基礎(chǔ),所有新的設(shè)計模式都是基于MVC進行的改進。
3.#import跟 #include 有什么區(qū)別,@class呢,#import<> 跟 #import””有什么區(qū)別?
1). #import是Objective-C導入頭文件的關(guān)鍵字,#include是C/C++導入頭文件的關(guān)鍵字,使用#import頭文件會自動只導入一次,不會重復導入。
2). @class告訴編譯器某個類的聲明,當執(zhí)行時,才去查看類的實現(xiàn)文件,可以解決頭文件的相互包含。
3). #import<>用來包含系統(tǒng)的頭文件,#import””用來包含用戶頭文件。
4.frame 和 bounds 有什么不同?
frame指的是:該view在父view坐標系統(tǒng)中的位置和大小。(參照點是父view的坐標系統(tǒng)) bounds指的是:該view在本身坐標系統(tǒng)中的位置和大小。(參照點是本身坐標系統(tǒng))
5.Objective-C的類可以多重繼承么?可以實現(xiàn)多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好?為什么?
答:Objective-C的類不可以多重繼承;可以實現(xiàn)多個接口(協(xié)議);Category是類別;一般情況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其他類與原有類的關(guān)系。
6.@property 的本質(zhì)是什么?ivar、getter、setter 是如何生成并添加到這個類中的
@property 的本質(zhì)是什么?
@property = ivar + getter + setter;
“屬性” (property)有兩大概念:ivar(實例變量)、getter+setter(存取方法)
“屬性” (property)作為 Objective-C 的一項特性,主要的作用就在于封裝對象中的數(shù)據(jù)。 Objective-C 對象通常會把其所需要的數(shù)據(jù)保存為各種實例變量。實例變量一般通過“存取方法”(access method)來訪問。其中,“獲取方法” (getter)用于讀取變量值,而“設(shè)置方法” (setter)用于寫入變量值。
7.@property中有哪些屬性關(guān)鍵字?/ @property 后面可以有哪些修飾符?
屬性可以擁有的特質(zhì)分為四類:
- 原子性--- nonatomic 特質(zhì)
- 讀/寫權(quán)限---readwrite(讀寫)、readonly (只讀)
- 內(nèi)存管理語義---assign、strong、 weak、unsafe_unretained、copy
- 方法名---getter= 、setter=
- 不常用的:nonnull,null_resettable,nullable
8.屬性關(guān)鍵字 readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那種情況下用?
1). readwrite 是可讀可寫特性。需要生成getter方法和setter方法。
2). readonly 是只讀特性。只會生成getter方法,不會生成setter方法,不希望屬性在類外改變。
3). assign 是賦值特性。setter方法將傳入?yún)?shù)賦值給實例變量;僅設(shè)置變量時,assign用于基本數(shù)據(jù)類型。
4). retain(MRC)/strong(ARC) 表示持有特性。setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retaincount會+1。
5). copy 表示拷貝特性。setter方法將傳入對象復制一份,需要完全一份新的變量時。
6). nonatomic 非原子操作。決定編譯器生成的setter和getter方法是否是原子操作,atomic表示多線程安全,一般使用nonatomic,效率高。
9.什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?
- 1.在 ARC 中,在有可能出現(xiàn)循環(huán)引用的時候,往往要通過讓其中一端使用 weak 來解決,比如: delegate 代理屬性。
- 2.自身已經(jīng)對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak,自定義 IBOutlet 控件屬性一般也使用 weak;當然,也可以使用strong。
10.IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak?
- 因為父控件的subViews數(shù)組已經(jīng)對它有一個強引用。
不同點:
- assign 可以用非 OC 對象,而 weak 必須用于 OC 對象。
- weak 表明該屬性定義了一種“非擁有關(guān)系”。在屬性所指的對象銷毀時,屬性值會自動清空(nil)。
11.怎么用 copy 關(guān)鍵字?
- 用途
1. NSString、NSArray、NSDictionary 等等經(jīng)常使用copy關(guān)鍵字,是因為他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary;
2. block 也經(jīng)常使用 copy 關(guān)鍵字。
- 說明:
block 使用 copy 是從 MRC 遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但寫上 copy 也無傷大雅,還能時刻提醒我們:編譯器自動對 block 進行了 copy 操作。如果不寫 copy ,該類的調(diào)用者有可能會忘記或者根本不知道“編譯器會自動對 block 進行了 copy 操作”,他們有可能會在調(diào)用之前自行拷貝屬性值。這種操作多余而低效。
12.用@property聲明的 NSString / NSArray / NSDictionary 經(jīng)常使用 copy 關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問題?
用 @property 聲明 NSString、NSArray、NSDictionary 經(jīng)常使用 copy 關(guān)鍵字,是因為他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操作(就是把可變的賦值給不可變的),為確保對象中的字符串值不會無意間變動,應該在設(shè)置新屬性值時拷貝一份
1. 因為父類指針可以指向子類對象,使用 copy 的目的是為了讓本對象的屬性不受外界影響,使用 copy 無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本。
2. 如果我們使用是 strong ,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性。
//總結(jié):使用copy的目的是,防止把可變類型的對象賦值給不可變類型的對象時,可變類型對象的值發(fā)送變化會無意間篡改不可變類型對象原來的值。
####13.淺拷貝和深拷貝的區(qū)別?
答: 淺拷貝:只復制指向?qū)ο蟮闹羔槪粡椭埔脤ο蟊旧怼?深拷貝:復制引用對象本身。內(nèi)存中存在了兩份獨立對象本身,當修改A時,A_copy不變。
####14.系統(tǒng)對象的 copy 與 mutableCopy 方法
不管是集合類對象(NSArray、NSDictionary、NSSet ... 之類的對象),還是非集合類對象(NSString, NSNumber ... 之類的對象),接收到copy和mutableCopy消息時,都遵循以下準則:
1. copy 返回的是不可變對象(immutableObject);如果用copy返回值調(diào)用mutable對象的方法就會crash。
2. mutableCopy 返回的是可變對象(mutableObject)。
一、非集合類對象的copy與mutableCopy 在非集合類對象中,對不可變對象進行copy操作,是指針復制,mutableCopy操作是內(nèi)容復制; 對可變對象進行copy和mutableCopy都是內(nèi)容復制。用代碼簡單表示如下:
NSString *str = @"hello word!";
NSString *strCopy = [str copy] // 指針復制,strCopy與str的地址一樣
NSMutableString *strMCopy = [str mutableCopy] // 內(nèi)容復制,strMCopy與str的地址不一樣
NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"];
NSString *strCopy = [mutableStr copy] // 內(nèi)容復制
NSMutableString *strMCopy = [mutableStr mutableCopy] // 內(nèi)容復制
二、集合類對象的copy與mutableCopy (同上)
在集合類對象中,對不可變對象進行copy操作,是指針復制,mutableCopy操作是內(nèi)容復制;
對可變對象進行copy和mutableCopy都是內(nèi)容復制。但是:集合對象的內(nèi)容復制僅限于對象本身,對集合內(nèi)的對象元素仍然是指針復制。(即單層內(nèi)容復制)
NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"];
NSArray *copyArr = [arr copy]; // 指針復制
NSMutableArray *mCopyArr = [arr mutableCopy]; //單層內(nèi)容復制
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArr = [mutableArr copy]; // 單層內(nèi)容復制
NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 單層內(nèi)容復制
【總結(jié)一句話】: 只有對不可變對象進行copy操作是指針復制(淺復制),其它情況都是內(nèi)容復制(深復制)!
15.這個寫法會出什么問題:@property (nonatomic, copy) NSMutableArray *arr;
問題:添加,刪除,修改數(shù)組內(nèi)的元素的時候,程序會因為找不到對應的方法而崩潰。
//如:-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460
// copy后返回的是不可變對象(即 arr 是 NSArray 類型,NSArray 類型對象不能調(diào)用 NSMutableArray 類型對象的方法)
原因:是因為 copy 就是復制一個不可變 NSArray 的對象,不能對 NSArray 對象進行添加/修改。
16.如何讓自己的類用 copy 修飾符?如何重寫帶 copy 關(guān)鍵字的 setter?
若想令自己所寫的對象具有拷貝功能,則需實現(xiàn) NSCopying 協(xié)議。如果自定義的對象分為可變版本與不可變版本,那么就要同時實現(xiàn) NSCopying 與 NSMutableCopying 協(xié)議。
具體步驟:
- 需聲明該類遵從 NSCopying 協(xié)議
- 實現(xiàn) NSCopying 協(xié)議的方法。
// 該協(xié)議只有一個方法:
(id)copyWithZone:(NSZone *)zone;
// 注意:使用 copy 修飾符,調(diào)用的是copy方法,其實真正需要實現(xiàn)的是 “copyWithZone” 方法。
17.寫一個 setter 方法用于完成 @property (nonatomic, retain) NSString *name,寫一個 setter 方法用于完成 @property (nonatomic, copy) NSString *name
答:
// retain
(void)setName:(NSString *)str {
[str retain];
[_name release];
_name = str;
}
// copy
(void)setName:(NSString *)str {
id t = [str copy];
[_name release];
_name = t;
}
18.@synthesize 和 @dynamic 分別有什么作用?
@property有兩個對應的詞,一個是@synthesize(合成實例變量),一個是@dynamic。
如果@synthesize和@dynamic都沒有寫,那么默認的就是 @synthesize var = _var;
// 在類的實現(xiàn)代碼里通過 @synthesize 語法可以來指定實例變量的名字。(@synthesize var = _newVar;)
@synthesize 的語義是如果你沒有手動實現(xiàn)setter方法和getter方法,那么編譯器會自動為你加上這兩個方法。
@dynamic 告訴編譯器,屬性的setter與getter方法由用戶自己實現(xiàn),不自動生成(如,@dynamic var)。
19.常見的 Objective-C 的數(shù)據(jù)類型有那些,和C的基本數(shù)據(jù)類型有什么區(qū)別?如:NSInteger和int
答:
Objective-C的數(shù)據(jù)類型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,這些都是class,創(chuàng)建后便是對象,而C語言的基本數(shù)據(jù)類型int,只是一定字節(jié)的內(nèi)存空間,用于存放數(shù)值;NSInteger是基本數(shù)據(jù)類型,并不是NSNumber的子類,當然也不是NSObject的子類。NSInteger是基本數(shù)據(jù)類型Int或者Long的別名(NSInteger的定義typedef long NSInteger),它的區(qū)別在于,NSInteger會根據(jù)系統(tǒng)是32位還是64位來決定是本身是int還是long。
20.id 聲明的對象有什么特性?
答:id 聲明的對象具有運行時的特性,即可以指向任意類型的Objcetive-C的對象。
21.Objective-C 如何對內(nèi)存管理的,說說你的看法和解決方法?
答:Objective-C的內(nèi)存管理主要有三種方式ARC(自動內(nèi)存計數(shù))、手動內(nèi)存計數(shù)、內(nèi)存池。
自動內(nèi)存計數(shù)ARC:由Xcode自動在App編譯階段,在代碼中添加內(nèi)存管理代碼。
手動內(nèi)存計數(shù)MRC:遵循內(nèi)存誰申請、誰釋放;誰添加,誰釋放的原則。
內(nèi)存釋放池Release Pool:把需要釋放的內(nèi)存統(tǒng)一放在一個池子中,當池子被抽干后(drain),池子中所有的內(nèi)存空間也被自動釋放掉。內(nèi)存池的釋放操作分為自動和手動。自動釋放受runloop機制影響。
22.Objective-C 中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時執(zhí)行代碼、方法又是什么?
答:線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;在主線程執(zhí)行代碼,方法是performSelectorOnMainThread,如果想延時執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone:
23.Category(類別)、 Extension(擴展)和繼承的區(qū)別
區(qū)別:
- 分類有名字,類擴展沒有分類名字,是一種特殊的分類。
- 分類只能擴展方法(屬性僅僅是聲明,并沒真正實現(xiàn)),類擴展可以擴展屬性、成員變量和方法。
- 繼承可以增加,修改或者刪除方法,并且可以增加屬性。
24.我們說的OC是動態(tài)運行時語言是什么意思?
答:主要是將數(shù)據(jù)類型的確定由編譯時,推遲到了運行時。簡單來說, 運行時機制使我們直到運行時才去決定一個對象的類別,以及調(diào)用該類別對象指定方法。
25.為什么我們常見的delegate屬性都用是week而不是retain/strong?
答:是為了防止delegate兩端產(chǎn)生不必要的循環(huán)引用。 @property (nonatomic, weak) id delegate;
26.什么時候用delete,什么時候用Notification?
Delegate(委托模式):1對1的反向消息通知功能。 Notification(通知模式):只想要把消息發(fā)送出去,告知某些狀態(tài)的變化。但是并不關(guān)心誰想要知道這個
27.什么是 KVO 和 KVC?
1). KVC(Key-Value-Coding):鍵值編碼 是一種通過字符串間接訪問對象的方式(即給屬性賦值) 舉例說明: stu.name = @"張三" // 點語法給屬性賦值 [stu setValue:@"張三" forKey:@"name"]; // 通過字符串使用KVC方式給屬性賦值 stu1.nameLabel.text = @"張三"; [stu1 setValue:@"張三" forKey:@"nameLabel.text"]; // 跨層賦值 2). KVO(key-Value-Observing):鍵值觀察機制 他提供了觀察某一屬性變化的方法,極大的簡化了代碼。 KVO只能被KVC觸發(fā),包括使用setValue:forKey:方法和點語法。
// 通過下方方法為屬性添加KVO觀察
- (void)addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(nullable void *)context;
// 當被觀察的屬性發(fā)送變化時,會自動觸發(fā)下方方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{}
KVC 和 KVO 的 keyPath 可以是屬性、實例變量、成員變量。
28.KVC的底層實現(xiàn)?
- 當一個對象調(diào)用setValue方法時,方法內(nèi)部會做以下操作:
- 檢查是否存在相應的key的set方法,如果存在,就調(diào)用set方法。
- 如果set方法不存在,就會查找與key相同名稱并且?guī)聞澗€的成員變量,如果有,則直接給成員變量屬性賦值。
- 如果沒有找到_key,就會查找相同名稱的屬性key,如果有就直接賦值。
- 如果還沒有找到,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
- 這些方法的默認實現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們。
29.KVO的底層實現(xiàn)
KVO基于runtime機制實現(xiàn)。
30.ViewController生命周期
按照執(zhí)行順序排列:
- initWithCoder:通過nib文件初始化時觸發(fā)。
- awakeFromNib:nib文件被加載的時候,會發(fā)生一個awakeFromNib的消息到nib文件中的每個對象。
- loadView:開始加載視圖控制器自帶的view。
- viewDidLoad:視圖控制器的view被加載完成。
- viewWillAppear:視圖控制器的view將要顯示在window上。
- updateViewConstraints:視圖控制器的 view開始更新AutoLayout約束。
- viewWillLayoutSubviews:視圖控制器的view將要更新內(nèi)容視圖的位置。
- viewDidLayoutSubviews:視圖控制器的view已經(jīng)更新視圖的位置。
- viewDidAppear:視圖控制器的view已經(jīng)展示到window上。
- viewWillDisappear:視圖控制器的view將要從window上消失。
- viewDidDisappear:視圖控制器的view已經(jīng)從window上消失
31.方法和選擇器有何不同?
selector是一個方法的名字,方法是一個組合體,包含了名字和實現(xiàn)。
32.你是否接觸過OC中的反射機制?簡單聊一下概念和使用
- class反射
- 通過類名的字符串形式實例化對象。
- Class class =NSClassFromString(@"student");
- Student *stu = [[class alloc] init];
- 將類名變?yōu)樽址?/li>
- Class class =[Student class];
- NSString *className =NSStringFromClass(class);
- SEL的反射
- 通過方法的字符串形式實例化方法。
- SEL selector = - -NSSelectorFromString(@"setName");
- [stu performSelector:selector withObject:@"Mike"];
- 將方法變成字符串。
- NSStringFromSelector(@selector*(setName:));
- 調(diào)用方法有兩種方式:
- 直接通過方法名來調(diào)用。[person show];
- 間接的通過SEL數(shù)據(jù)來調(diào)用 SEL aaa = @selector(show); [person performSelector:aaa];
33.如何對iOS設(shè)備進行性能測試?
答: Profile-> Instruments ->Time Profiler
34.開發(fā)項目時你是怎么檢查內(nèi)存泄露?
- 靜態(tài)分析 analyze。
- instruments工具里面有個leak可以動態(tài)分析。
35.什么是懶加載?
- 答:懶加載就是只在用到的時候才去初始化。也可以理解成延時加載。
- 我覺得最好也最簡單的一個例子就是tableView中圖片的加載顯示了, 一個延時加載, 避免內(nèi)存過高,一個異步加載,避免線程堵塞提高用戶體驗。
36.類變量的 @public,@protected,@private,@package 聲明各有什么含義?
- @public 任何地方都能訪問;
- @protected 該類和子類中訪問,是默認的;
- @private 只能在本類中訪問;
- @package 本包內(nèi)使用,跨包不可以。
37.什么是謂詞?
- 謂詞就是通過NSPredicate給定的邏輯條件作為約束條件,完成對數(shù)據(jù)的篩選。
- //定義謂詞對象,謂詞對象中包含了過濾條件(過濾條件比較多)
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];
- //使用謂詞條件過濾數(shù)組中的元素,過濾之后返回查詢的結(jié)果
- NSArray *array = [persons filteredArrayUsingPredicate:predicate];
38.isa指針問題
isa:是一個Class 類型的指針. 每個實例對象有個isa的指針,他指向?qū)ο蟮念?而Class里也有個isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。當類方法被調(diào) 用時,先會從本身查找類方法的實現(xiàn),如果沒有,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass)。根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)。
39.如何訪問并修改一個類的私有屬性?
- 一種是通過KVC獲取。
- 通過runtime訪問并修改私有屬性。
40.一個objc對象的isa的指針指向什么?有什么作用?
答:指向他的類對象,從而可以找到對象上的方法。
41.下面的代碼輸出什么?
@implementation Son : Father
- (id)init {
if (self = [super init]) {
NSLog(@"%@", NSStringFromClass([self class])); // Son
NSLog(@"%@", NSStringFromClass([super class])); // Son
}
return self;
}
@end
解析:
- self 是類的隱藏參數(shù),指向當前調(diào)用方法的這個類的實例。
- super是一個Magic Keyword,它本質(zhì)是一個編譯器標示符,和self是指向的同一個消息接收者。
- 不同的是:super會告訴編譯器,調(diào)用class這個方法時,要去父類的方法,而不是本類里的。
- 上面的例子不管調(diào)用[self class]還是[super class],接受消息的對象都是當前 Son *obj 這個對象。
42.寫一個完整的代理,包括聲明、實現(xiàn)
// 創(chuàng)建
@protocol MyDelagate
@required
-(void)eat:(NSString *)foodName;
@optional
-(void)run;
@end
// 聲明 .h
@interface person: NSObject<MyDelagate>
@end
// 實現(xiàn) .m
@implementation person
- (void)eat:(NSString *)foodName {
NSLog(@"吃:%@!", foodName);
}
- (void)run {
NSLog(@"run!");
}
@end
43.isKindOfClass、isMemberOfClass、selector作用分別是什么
- isKindOfClass:作用是某個對象屬于某個類型或者繼承自某類型。
- isMemberOfClass:某個對象確切屬于某個類型。
- selector:通過方法名,獲取在內(nèi)存中的函數(shù)的入口地址
44.delegate 和 notification 的區(qū)別
- 二者都用于傳遞消息,不同之處主要在于一個是一對一的,另一個是一對多的。
- notification通過維護一個array,實現(xiàn)一對多消息的轉(zhuǎn)發(fā)。
- delegate需要兩者之間必須建立聯(lián)系,不然沒法調(diào)用代理的方法;notification不需要兩者之間有聯(lián)系。
45.什么是block?
閉包(block):閉包就是獲取其它函數(shù)局部變量的匿名函數(shù)。 block反向傳值 在控制器間傳值可以使用代理或者block,使用block相對來說簡潔。 在前一個控制器的touchesBegan:方法內(nèi)實現(xiàn)如下代碼。
// OneViewController.m
TwoViewController *twoVC = [[TwoViewController alloc] init];
twoVC.valueBlcok = ^(NSString *str) {
NSLog(@"OneViewController拿到值:%@", str);
};
[self presentViewController:twoVC animated:YES completion:nil];
// TwoViewController.h (在.h文件中聲明一個block屬性)
@property (nonatomic ,strong) void(^valueBlcok)(NSString *str);
// TwoViewController.m (在.m文件中實現(xiàn)方法)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 傳值:調(diào)用block
if (_valueBlcok) {
_valueBlcok(@"123456");
}
}
46.block的注意點
- 在block內(nèi)部使用外部指針且會造成循環(huán)引用情況下,需要用__week修飾外部指針:
- __weak typeof(self) weakSelf = self;
- 在block內(nèi)部如果調(diào)用了延時函數(shù)還使用弱指針會取不到該指針,因為已經(jīng)被銷毀了,需要在block內(nèi)部再將弱指針重新強引用一下。
- __strong typeof(self) strongSelf = weakSelf;
- 如果需要在block內(nèi)部改變外部棧區(qū)變量的話,需要在用__block修飾外部變量。
47.BAD_ACCESS在什么情況下出現(xiàn)?
答:這種問題在開發(fā)時經(jīng)常遇到。原因是訪問了野指針,比如訪問已經(jīng)釋放對象的成員變量或者發(fā)消息、死循環(huán)等。
48.你一般是怎么用Instruments的?
- Instruments里面工具很多,常用:
- Time Profiler: 性能分析
- Zombies:檢查是否訪問了僵尸對象,但是這個工具只能從上往下檢查,不智能。
- Allocations:用來檢查內(nèi)存,寫算法的那批人也用這個來檢查。
- Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露。
49.iOS中常用的數(shù)據(jù)存儲方式有哪些?
數(shù)據(jù)存儲有四種方案:NSUserDefault、KeyChain、file、DB。 其中File有三種方式:plist、Archive(歸檔) DB包括:SQLite、FMDB、CoreData
50.iOS的沙盒目錄結(jié)構(gòu)是怎樣的?
沙盒結(jié)構(gòu):
1). Application:存放程序源文件,上架前經(jīng)過數(shù)字簽名,上架后不可修改。
2). Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù)。(這里不能存緩存文件,否則上架不被通過)
3). Library:
Caches:存放體積大又不需要備份的數(shù)據(jù)。(常用的緩存路徑)
Preference:設(shè)置目錄,iCloud會備份設(shè)置信息。
4). tmp:存放臨時文件,不會被備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能。
````
###End
有點老了的面試題,但是還是很具體的,希望看了對你有所幫助。最后就是點點贊,點點關(guān)注呀。更多請關(guān)注主頁獲取。