iOS 面試必看,最全梳理(下)

鏈接:http://www.itdecent.cn/p/5d2163640e26


如何進(jìn)行網(wǎng)絡(luò)消息推送


一種是Apple自己提供的通知服務(wù)(APNS服務(wù)器)、一種是用第三方推送機(jī)制。

首先應(yīng)用發(fā)送通知,系統(tǒng)彈出提示框詢問用戶是否允許,當(dāng)用戶允許后向蘋果服務(wù)器(APNS)請求deviceToken,并由蘋果服務(wù)器發(fā)送給自己的應(yīng)用,自己的應(yīng)用將DeviceToken發(fā)送自己的服務(wù)器,自己服務(wù)器想要發(fā)送網(wǎng)絡(luò)推送時將deviceToken以及想要推送的信息發(fā)送給蘋果服務(wù)器,蘋果服務(wù)器將信息發(fā)送給應(yīng)用。

推送信息內(nèi)容,總?cè)萘坎怀^256個字節(jié);

iOS SDK本身提供的APNS服務(wù)器推送,它可以直接推送給目標(biāo)用戶并根據(jù)您的方式彈出提示。

優(yōu)點(diǎn):不論應(yīng)用是否開啟,都會發(fā)送到手機(jī)端;

缺點(diǎn):消息推送機(jī)制是蘋果服務(wù)端控制,個別時候可能會有延遲,因?yàn)樘O果服務(wù)器也有隊(duì)列來處理所有的消息請求;

第三方推送機(jī)制,普遍使用Socket機(jī)制來實(shí)現(xiàn),幾乎可以達(dá)到即時的發(fā)送到目標(biāo)用戶手機(jī)端,適用于即時通訊類應(yīng)用。

優(yōu)點(diǎn):實(shí)時的,取決于心跳包的節(jié)奏;

缺點(diǎn):iOS系統(tǒng)的限制,應(yīng)用不能長時間的后臺運(yùn)行,所以應(yīng)用關(guān)閉的情況下這種推送機(jī)制不可用。


網(wǎng)絡(luò)七層協(xié)議


應(yīng)用層:

1.用戶接口、應(yīng)用程序;

2.Application典型設(shè)備:網(wǎng)關(guān);

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TELNET、FTP、HTTP

表示層:

1.數(shù)據(jù)表示、壓縮和加密presentation

2.典型設(shè)備:網(wǎng)關(guān)

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:ASCLL、PICT、TIFF、JPEG|MPEG

4.表示層相當(dāng)于一個東西的表示,表示的一些協(xié)議,比如圖片、聲音和視頻MPEG。

會話層:

1.會話的建立和結(jié)束;

2.典型設(shè)備:網(wǎng)關(guān);

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:RPC、SQL、NFS、X WINDOWS、ASP

傳輸層:

1.主要功能:端到端控制Transport;

2.典型設(shè)備:網(wǎng)關(guān);

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:TCP、UDP、SPX

網(wǎng)絡(luò)層:

1.主要功能:路由、尋址Network;

2.典型設(shè)備:路由器;

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:IP、IPX、APPLETALK、ICMP;

數(shù)據(jù)鏈路層:

1.主要功能:保證無差錯的疏忽鏈路的data link;

2.典型設(shè)備:交換機(jī)、網(wǎng)橋、網(wǎng)卡;

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:802.2、802.3ATM、HDLC、FRAME RELAY;

物理層:

1.主要功能:傳輸比特流Physical;

2.典型設(shè)備:集線器、中繼器

3.典型協(xié)議、標(biāo)準(zhǔn)和應(yīng)用:V.35、EIA/TIA-232.


對NSUserDefaults的理解


NSUserDefaults:系統(tǒng)提供的一種存儲數(shù)據(jù)的方式,主要用于保存少量的數(shù)據(jù),默認(rèn)存儲到library下的Preferences文件夾。


SDWebImage原理


調(diào)用類別的方法:


從內(nèi)存中(字典)找圖片(當(dāng)這個圖片在本次程序加載過),找到直接使用;

從沙盒中找,找到直接使用,緩存到內(nèi)存。

從網(wǎng)絡(luò)上獲取,使用,緩存到內(nèi)存,緩存到沙盒。


OC中是否有二維數(shù)組,如何實(shí)現(xiàn)二維數(shù)組


OC中沒有二維數(shù)組,可通過嵌套數(shù)組實(shí)現(xiàn)二維數(shù)組。


LayoutSubViews在什么時候被調(diào)用?


當(dāng)View本身的frame改變時,會調(diào)用這個方法。


深拷貝和淺拷貝


如果對象有個指針型成員變量指向內(nèi)存中的某個資源,那么如何復(fù)制這個對象呢?你會只是復(fù)制指針的值傳給副本的新對象嗎?指針只是存儲內(nèi)存中資源地址的占位符。在復(fù)制操作中,如果只是將指針復(fù)制給新對象,那么底層的資源實(shí)際上仍然由兩個實(shí)例在共享。




示例圖1


淺復(fù)制:兩個實(shí)例的指針仍指向內(nèi)存中的同一資源,只復(fù)制指針值而不是實(shí)際資源;

深復(fù)制:不僅復(fù)制指針值,還復(fù)制指向指針?biāo)赶虻馁Y源。如下圖:



示例圖2


單例模式理解與使用


單例模式是一種常用設(shè)計(jì)模式,單例模式是一個類在系統(tǒng)中只有一個實(shí)例對象。通過全局的一個入口點(diǎn)對這個實(shí)例對象進(jìn)行訪問;

iOS中單例模式的實(shí)現(xiàn)方式一般分為兩種:非ARC和ARC+GCD。


對沙盒的理解


每個iOS應(yīng)用都被限制在“沙盒”中,沙盒相當(dāng)于一個加了僅主人可見權(quán)限的文件夾,及時在應(yīng)用程序安裝過程中,系統(tǒng)為每個單獨(dú)的應(yīng)用程序生成它的主目錄和一些關(guān)鍵的子目錄。蘋果對沙盒有幾條限制:


1. 應(yīng)用程序在自己的沙盒中運(yùn)作,但是不能訪問任何其他應(yīng)用程序的沙盒;

2. 應(yīng)用之間不能共享數(shù)據(jù),沙盒里的文件不能被復(fù)制到其他

應(yīng)用程序的文件夾中,也不能把其他應(yīng)用文件夾復(fù)制到沙盒中;

3. 蘋果禁止任何讀寫沙盒以外的文件,禁止應(yīng)用程序?qū)?nèi)容寫到沙盒以外的文件夾中;

4. 沙盒目錄里有三個文件夾:Documents——存儲

應(yīng)用程序的數(shù)據(jù)文件,存儲用戶數(shù)據(jù)或其他定期備份的信息;

Library下有兩個文件夾,Caches存儲應(yīng)用程序再次啟動所需的信息,

Preferences包含應(yīng)用程序的偏好設(shè)置文件,不可在這更改偏好設(shè)置;

temp存放臨時文件即應(yīng)用程序再次啟動不需要的文件。


獲取沙盒根目錄的方法,有幾種方法:用NSHomeDirectory獲取。

獲取Document路徑:

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).


對瀑布流的理解


首先圖片的寬度都是一樣的,1.將圖片等比例壓縮,讓圖片不變形;2.計(jì)算圖片最低應(yīng)該擺放的位置,哪一列低就放在哪;3.進(jìn)行最優(yōu)排列,在ScrollView的基礎(chǔ)上添加兩個tableView,然后將之前所計(jì)算的scrollView的高度通過tableView展示出來。

如何使用兩個TableView產(chǎn)生聯(lián)動:將兩個tableView的滾動事件禁止掉,最外層scrollView滾動時將兩個TableView跟著滾動,并且更改contentOffset,這樣產(chǎn)生效果滾動的兩個tableView。


ViewController 的 loadView,、viewDidLoad,、viewDidUnload 分別是在什么時候調(diào)用的?


viewDidLoad在view從nib文件初始化時調(diào)用,loadView在controller的view為nil時調(diào)用。

此方法在編程實(shí)現(xiàn)view時調(diào)用,view控制器默認(rèn)會注冊memory warning notification,當(dāng)view controller的任何view沒有用的時候,viewDidUnload會被調(diào)用,在這里實(shí)現(xiàn)將retain的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會負(fù)責(zé)release 。


關(guān)鍵字volatile有什么含意?并給出三個不同的例子:


一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:

? 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器);

?一個中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables);

? 多線程應(yīng)用中被幾個任務(wù)共享的變量。


@synthesize、@dynamic的理解


@synthesize是系統(tǒng)自動生成getter和setter屬性聲明;@synthesize的意思是,除非開發(fā)人員已經(jīng)做了,否則由編譯器生成相應(yīng)的代碼,以滿足屬性聲明;

@dynamic是開發(fā)者自已提供相應(yīng)的屬性聲明,@dynamic意思是由開發(fā)人員提供相應(yīng)的代碼:對于只讀屬性需要提供setter,對于讀寫屬性需要提供 setter 和getter。查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由用戶自己實(shí)現(xiàn), 不自動生成。


frame和bounds有什么不同?


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))


view的touch事件有哪些?


?- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

?- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

?- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;



自定義實(shí)現(xiàn)UITabbarController的原理


運(yùn)用字典,點(diǎn)擊五個按鈕的一個可以從字典里選擇一個控制器對象,將其View顯示到主控制器視圖上。


iOS中的響應(yīng)者鏈的工作原理


每一個應(yīng)用有一個響應(yīng)者鏈,我們的視圖結(jié)構(gòu)是一個N叉樹(一個視圖可以有多個子視圖,一個子視圖同一時刻只有一個父視圖),而每一個繼承UIResponder的對象都可以在這個N叉樹中扮演一個節(jié)點(diǎn)。

當(dāng)葉節(jié)點(diǎn)成為最高響應(yīng)者的時候,從這個葉節(jié)點(diǎn)開始往其父節(jié)點(diǎn)開始追朔出一條鏈,那么對于這一個葉節(jié)點(diǎn)來講,這一條鏈就是當(dāng)前的響應(yīng)者鏈。響應(yīng)者鏈將系統(tǒng)捕獲到的UIEvent與UITouch從葉節(jié)點(diǎn)開始層層向下分發(fā),期間可以選擇停止分發(fā),也可以選擇繼續(xù)向下分發(fā)。

如需了解更多細(xì)節(jié),請讀這篇文章。


View和View之間傳值方式


對象的property屬性傳值;

方法參數(shù)傳值;

NSUserDefault傳值;

塊傳值。


property屬性的修飾符的作用


getter=getName、setter=setName:設(shè)置setter與getter的方法名;

readwrite、readonly:設(shè)置可供訪問級別;

assign:方法直接賦值,不進(jìn)行任何retain操作,為了解決原類型與環(huán)循引用問題;

retain:其setter方法對參數(shù)進(jìn)行release舊值再retain新值,所有實(shí)現(xiàn)都是這個順序;

copy:其setter方法進(jìn)行copy操作,與retain處理流程一樣,先對舊值release,再copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機(jī)制。

nonatomic:非原子性訪問,不加同步, 多線程并發(fā)訪問會提高性能。注意,如果不加此屬性,則默認(rèn)是兩個訪問方法都為原子型事務(wù)訪問。


對于Run Loop的理解


RunLoop,是多線程的法寶,即一個線程一次只能執(zhí)行一個任務(wù),執(zhí)行完任務(wù)后就會退出線程。主線程執(zhí)行完即時任務(wù)時會繼續(xù)等待接收事件而不退出。非主線程通常來說就是為了執(zhí)行某一任務(wù)的,執(zhí)行完畢就需要?dú)w還資源,因此默認(rèn)是不運(yùn)行RunLoop的;

每一個線程都有其對應(yīng)的RunLoop,只是默認(rèn)只有主線程的RunLoop是啟動的,其它子線程的RunLoop默認(rèn)是不啟動的,若要啟動則需要手動啟動;

在一個單獨(dú)的線程中,如果需要在處理完某個任務(wù)后不退出,繼續(xù)等待接收事件,則需要啟用RunLoop;

NSRunLoop提供了一個添加NSTimer的方法,可以指定Mode,如果要讓任何情況下都回調(diào),則需要設(shè)置Mode為Common模式;

實(shí)質(zhì)上,對于子線程的runloop默認(rèn)是不存在的,因?yàn)樘O果采用了懶加載的方式。如果我們沒有手動調(diào)用[NSRunLoop currentRunLoop]的話,就不會去查詢是否存在當(dāng)前線程的RunLoop,也就不會去加載,更不會創(chuàng)建。


SQLite中常用的SQL語句


創(chuàng)建表:creat table 表名 (字段名 字段數(shù)據(jù)類型 是否為主鍵, 字段名 字段數(shù)據(jù)類型, 字段名 字段數(shù)據(jù)類型…);

增: insert into 表名 (字段1, 字段2…) values (值1, 值2…);

刪: delete from 表名 where 字段 = 值;


XIB與Storyboards的優(yōu)缺點(diǎn)


優(yōu)點(diǎn):


XIB:在編譯前就提供了可視化界面,可以直接拖控件,也可以直接給控件添加約束,更直觀一些,而且類文件中就少了創(chuàng)建控件的代碼,確實(shí)簡化不少,通常每個XIB對應(yīng)一個類。

Storyboard:在編譯前提供了可視化界面,可拖控件,可加約束,在開發(fā)時比較直觀,而且一個storyboard可以有很多的界面,每個界面對應(yīng)一個類文件,通過storybard,可以直觀地看出整個App的結(jié)構(gòu)。


缺點(diǎn):


XIB:需求變動時,需要修改XIB很大,有時候甚至需要重新添加約束,導(dǎo)致開發(fā)周期變長。XIB載入相比純代碼自然要慢一些。對于比較復(fù)雜邏輯控制不同狀態(tài)下顯示不同內(nèi)容時,使用XIB是比較困難的。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時,如果XIB文件被發(fā)動,極易導(dǎo)致沖突,而且解決沖突相對要困難很多。

Storyboard:需求變動時,需要修改storyboard上對應(yīng)的界面的約束,與XIB一樣可能要重新添加約束,或者添加約束會造成大量的沖突,尤其是多團(tuán)隊(duì)開發(fā)。對于復(fù)雜邏輯控制不同顯示內(nèi)容時,比較困難。當(dāng)多人團(tuán)隊(duì)或者多團(tuán)隊(duì)開發(fā)時,大家會同時修改一個storyboard,導(dǎo)致大量沖突,解決起來相當(dāng)困難。


將字符串“2015-04-10”格式化日期轉(zhuǎn)為NSDate類型


NSString *timeStr = @"2015-04-10";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

formatter.dateFormat = @"yyyy-MM-dd";

formatter.timeZone = [NSTimeZone defaultTimeZone];

NSDate *date = [formatter dateFromString:timeStr];

// 2015-04-09 16:00:00 +0000

NSLog(@"%@", date);


隊(duì)列和多線程的使用原理


在iOS中隊(duì)列分為以下幾種:


串行隊(duì)列:隊(duì)列中的任務(wù)只會順序執(zhí)行;


dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);


并行隊(duì)列: 隊(duì)列中的任務(wù)通常會并發(fā)執(zhí)行;


dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);


全局隊(duì)列:是系統(tǒng)的,直接拿過來(GET)用就可以;與并行隊(duì)列類似;


dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);


主隊(duì)列:每一個應(yīng)用程序?qū)?yīng)唯一主隊(duì)列,直接GET即可;在多線程開發(fā)中,使用主隊(duì)列更新UI;


dispatch_queue_t q = dispatch_get_main_queue();


更多細(xì)節(jié)見下圖:




來自簡書


內(nèi)存的使用和優(yōu)化的注意事項(xiàng)


重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設(shè)置正確的reuseIdentifier,充分重用;

盡量把views設(shè)置為不透明:當(dāng)opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結(jié)果,可提高性能;

不要使用太復(fù)雜的XIB/Storyboard:載入時就會將XIB/storyboard需要的所有資源,包括圖片全部載入內(nèi)存,即使未來很久才會使用。那些相比純代碼寫的延遲加載,性能及內(nèi)存就差了很多;

選擇正確的數(shù)據(jù)結(jié)構(gòu):學(xué)會選擇對業(yè)務(wù)場景最合適的數(shù)組結(jié)構(gòu)是寫出高效代碼的基礎(chǔ)。比如,數(shù)組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。

gzip/zip壓縮:當(dāng)從服務(wù)端下載相關(guān)附件時,可以通過gzip/zip壓縮后再下載,使得內(nèi)存更小,下載速度也更快。

延遲加載:對于不應(yīng)該使用的數(shù)據(jù),使用延遲加載方式。對于不需要馬上顯示的視圖,使用延遲加載方式。比如,網(wǎng)絡(luò)請求失敗時顯示的提示界面,可能一直都不會使用到,因此應(yīng)該使用延遲加載。

數(shù)據(jù)緩存:對于cell的行高要緩存起來,使得reload數(shù)據(jù)時,效率也極高。而對于那些網(wǎng)絡(luò)數(shù)據(jù),不需要每次都請求的,應(yīng)該緩存起來,可以寫入數(shù)據(jù)庫,也可以通過plist文件存儲。

處理內(nèi)存警告:一般在基類統(tǒng)一處理內(nèi)存警告,將相關(guān)不用資源立即釋放掉

重用大開銷對象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它們。通常是作為屬性存儲起來,防止反復(fù)創(chuàng)建。

避免反復(fù)處理數(shù)據(jù):許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)。在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要;

使用Autorelease Pool:在某些循環(huán)創(chuàng)建臨時變量處理數(shù)據(jù)時,自動釋放池以保證能及時釋放內(nèi)存;

正確選擇圖片加載方式:詳情閱讀細(xì)讀UIImage加載方式


UIViewController的完整生命周期


-[ViewController initWithNibName:bundle:];

-[ViewController init];

-[ViewController loadView];

-[ViewController viewDidLoad];

-[ViewController viewWillDisappear:];

-[ViewController viewWillAppear:];

-[ViewController viewDidAppear:];

-[ViewController viewDidDisappear:];


UIImageView添加圓角


最直接的方法就是使用如下屬性設(shè)置:


imgView.layer.cornerRadius = 10;

// 這一行代碼是很消耗性能的

imgView.clipsToBounds = YES;


**這是離屏渲染(off-screen-rendering),消耗性能的**

給UIImage添加生成圓角圖片的擴(kuò)展API:這是on-screen-rendering


- (UIImage *)imageWithCornerRadius:(CGFloat)radius {

CGRect rect = (CGRect){0.f, 0.f, self.size};


UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);

CGContextAddPath(UIGraphicsGetCurrentContext(),

[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);

CGContextClip(UIGraphicsGetCurrentContext());


[self drawInRect:rect];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();


UIGraphicsEndImageContext();


return image;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容