iOS面試進階篇(三)

目錄
  • 網絡七層協議
  • 深拷貝和淺拷貝
  • 對沙盒的理解
  • 響應者鏈的工作原理
  • property屬性的修飾符的作用
  • 對于Run Loop的理解
  • 隊列和多線程的使用原理
  • 內存的使用和優化的注意事項
  • UIViewController的完整生命周期
1.網絡七層協議
  • 應用層:

    • 1.用戶接口、應用程序;
    • 2.Application典型設備:網關;
    • 3.典型協議、標準和應用:TELNET、FTP、HTTP
  • 表示層:

    • 1.數據表示、壓縮和加密presentation
    • 2.典型設備:網關
    • 3.典型協議、標準和應用:ASCLL、PICT、TIFF、JPEG|MPEG
    • 4.表示層相當于一個東西的表示,表示的一些協議,比如圖片、聲音和視頻MPEG。
  • 會話層:

    • 1.會話的建立和結束;
    • 2.典型設備:網關;
    • 3.典型協議、標準和應用:RPC、SQL、NFS、X WINDOWS、ASP
  • 傳輸層:

    • 1.主要功能:端到端控制Transport;
    • 2.典型設備:網關;
    • 3.典型協議、標準和應用:TCP、UDP、SPX
  • 網絡層:

    • 1.主要功能:路由、尋址Network;
    • 2.典型設備:路由器;
    • 3.典型協議、標準和應用:IP、IPX、APPLETALK、ICMP;
  • 數據鏈路層:

    • 1.主要功能:保證無差錯的疏忽鏈路的data link;
    • 2.典型設備:交換機、網橋、網卡;
    • 3.典型協議、標準和應用:802.2、802.3ATM、HDLC、FRAME RELAY;
  • 物理層:

    • 1.主要功能:傳輸比特流Physical;
    • 2.典型設備:集線器、中繼器
    • 3.典型協議、標準和應用:V.35、EIA/TIA-232.
2.對NSUserDefaults的理解

NSUserDefaults:系統提供的一種存儲數據的方式,主要用于保存少量的數據,默認存儲到library下的Preferences文件夾。

3.SDWebImage原理

調用類別的方法:

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

  • 從沙盒中找,找到直接使用,緩存到內存。

  • 從網絡上獲取,使用,緩存到內存,緩存到沙盒。

4.OC中是否有二維數組,如何實現二維數組?

OC中沒有二維數組,可通過嵌套數組實現二維數組。

5.LayoutSubViews在什么時候被調用?

當View本身的frame改變時,會調用這個方法。

6.深拷貝和淺拷貝
  • 如果對象有個指針型成員變量指向內存中的某個資源,那么如何復制這個對象呢?你會只是復制指針的值傳給副本的新對象嗎?指針只是存儲內存中資源地址的占位符。在復制操作中,如果只是將指針復制給新對象,那么底層的資源實際上仍然由兩個實例在共享。
image.png
  • 淺復制:兩個實例的指針仍指向內存中的同一資源,只復制指針值而不是實際資源;

  • 深復制:不僅復制指針值,還復制指向指針所指向的資源。如下圖:

image.png
7.單例模式理解與使用
  • 單例模式是一種常用設計模式,單例模式是一個類在系統中只有一個實例對象。通過全局的一個入口點對這個實例對象進行訪問;

  • iOS中單例模式的實現方式一般分為兩種:非ARC和ARC+GCD。

8.對沙盒的理解

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

  • 1.應用程序在自己的沙盒中運作,但是不能訪問任何其他應用程序的沙盒;

  • 2.應用之間不能共享數據,沙盒里的文件不能被復制到其他應用程序的文件夾中,也不能把其他應用文件夾復制到沙盒中;

  • 3.蘋果禁止任何讀寫沙盒以外的文件,禁止應用程序將內容寫到沙盒以外的文件夾中;

  • 4.沙盒目錄里有三個文件夾:

    • Documents——存儲;應用程序的數據文件,存儲用戶數據或其他定期備份的信息;
    • Library下有兩個文件夾,
      • Caches存儲應用程序再次啟動所需的信息,
      • Preferences包含應用程序的偏好設置文件,不可在這更改偏好設置;
    • temp存放臨時文件即應用程序再次啟動不需要的文件。
  • 5.獲取沙盒根目錄的方法,有幾種方法:用NSHomeDirectory獲取。

  • 6.獲取Document路徑:

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).
9.對瀑布流的理解
  • 首先圖片的寬度都是一樣的,1.將圖片等比例壓縮,讓圖片不變形;2.計算圖片最低應該擺放的位置,哪一列低就放在哪;3.進行最優排列,在ScrollView的基礎上添加兩個tableView,然后將之前所計算的scrollView的高度通過tableView展示出來。

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

10.ViewController 的 loadView、viewDidLoad、viewDidUnload 分別是在什么時候調用的?
  • viewDidLoad在view從nib文件初始化時調用

  • loadView在controller的view為nil時調用。

  • 此方法在編程實現view時調用,view控制器默認會注冊memory warning notification,當view controller的任何view沒有用的時候,viewDidUnload會被調用,在這里實現將retain的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會負責release 。

11.關鍵字volatile有什么含意?并給出三個不同的例子:

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

  • 1.并行設備的硬件寄存器(如:狀態寄存器);
  • 2.一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables);
  • 3.多線程應用中被幾個任務共享的變量。
12.@synthesize、@dynamic的理解
  • @synthesize是系統自動生成getter和setter屬性聲明;@synthesize的意思是,除非開發人員已經做了,否則由編譯器生成相應的代碼,以滿足屬性聲明;

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

13.frame和bounds有什么不同?
  • frame指的是:該view在父view坐標系統中的位置和大小。(參照點是父親的坐標系統)

  • bounds指的是:該view在本身坐標系統中的位置和大小。(參照點是本身坐標系統)

14.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;
15.自定義實現UITabbarController的原理

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

16.iOS中的響應者鏈的工作原理
  • 每一個應用有一個響應者鏈,我們的視圖結構是一個N叉樹(一個視圖可以有多個子視圖,一個子視圖同一時刻只有一個父視圖),而每一個繼承UIResponder的對象都可以在這個N叉樹中扮演一個節點。

  • 當葉節點成為最高響應者的時候,從這個葉節點開始往其父節點開始追朔出一條鏈,那么對于這一個葉節點來講,這一條鏈就是當前的響應者鏈。響應者鏈將系統捕獲到的UIEvent與UITouch從葉節點開始層層向下分發,期間可以選擇停止分發,也可以選擇繼續向下分發。

16.View和View之間傳值方式
  • 對象的property屬性傳值;
  • 方法參數傳值;
  • NSUserDefault傳值;
  • 塊傳值。
17.property屬性的修飾符的作用
  • getter=getName、setter=setName:設置setter與getter的方法名;
  • readwrite、readonly:設置可供訪問級別;
  • assign:方法直接賦值,不進行任何retain操作,為了解決原類型與環循引用問題;
  • retain:其setter方法對參數進行release舊值再retain新值,所有實現都是這個順序;
  • copy:其setter方法進行copy操作,與retain處理流程一樣,先對舊值release,再copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機制。
  • nonatomic:非原子性訪問,不加同步, 多線程并發訪問會提高性能。注意,如果不加此屬性,則默認是兩個訪問方法都為原子型事務訪問。
18.對于Run Loop的理解
  • RunLoop,是多線程的法寶,即一個線程一次只能執行一個任務,執行完任務后就會退出線程。主線程執行完即時任務時會繼續等待接收事件而不退出。非主線程通常來說就是為了執行某一任務的,執行完畢就需要歸還資源,因此默認是不運行RunLoop的;

  • 每一個線程都有其對應的RunLoop,只是默認只有主線程的RunLoop是啟動的,其它子線程的RunLoop默認是不啟動的,若要啟動則需要手動啟動;

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

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

  • 實質上,對于子線程的runloop默認是不存在的,因為蘋果采用了懶加載的方式。如果我們沒有手動調用[NSRunLoop currentRunLoop]的話,就不會去查詢是否存在當前線程的RunLoop,也就不會去加載,更不會創建。

19.SQLite中常用的SQL語句
  • 創建表:creat table 表名 (字段名 字段數據類型 是否為主鍵, 字段名 字段數據類型, 字段名 字段數據類型...);
  • 增: insert into 表名 (字段1, 字段2...) values (值1, 值2...);
  • 刪:delete from 表名 where 字段 = 值;
20.XIB與Storyboards的優缺點

優點:

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

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

缺點:

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

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

21 將字符串“2015-04-10”格式化日期轉為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);
22.隊列和多線程的使用原理

在iOS中隊列分為以下幾種:

  • 串行隊列:隊列中的任務只會順序執行;
dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);
  • 并行隊列: 隊列中的任務通常會并發執行;
dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);
  • 全局隊列:是系統的,直接拿過來(GET)用就可以;與并行隊列類似;
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  • 主隊列:每一個應用程序對應唯一主隊列,直接GET即可;在多線程開發中,使用主隊列更新UI;
dispatch_queue_t q = dispatch_get_main_queue();

更多細節見下圖:

CCDB5630-115E-4554-A183-54B7AB0756D5.png
23.內存的使用和優化的注意事項
  • 重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設置正確的reuseIdentifier,充分重用;
  • 盡量把views設置為不透明:當opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結果,可提高性能;
  • 不要使用太復雜的XIB/Storyboard:載入時就會將XIB/storyboard需要的所有資源,包括圖片全部載入內存,即使未來很久才會使用。那些相比純代碼寫的延遲加載,性能及內存就差了很多;
  • 選擇正確的數據結構:學會選擇對業務場景最合適的數組結構是寫出高效代碼的基礎。比如,數組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。
  • gzip/zip壓縮:當從服務端下載相關附件時,可以通過gzip/zip壓縮后再下載,使得內存更小,下載速度也更快。
  • 延遲加載:對于不應該使用的數據,使用延遲加載方式。對于不需要馬上顯示的視圖,使用延遲加載方式。比如,網絡請求失敗時顯示的提示界面,可能一直都不會使用到,因此應該使用延遲加載。
  • 數據緩存:對于cell的行高要緩存起來,使得reload數據時,效率也極高。而對于那些網絡數據,不需要每次都請求的,應該緩存起來,可以寫入數據庫,也可以通過plist文件存儲。
  • 處理內存警告:一般在基類統一處理內存警告,將相關不用資源立即釋放掉
  • 重用大開銷對象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它們。通常是作為屬性存儲起來,防止反復創建。
  • 避免反復處理數據:許多應用需要從服務器加載功能所需的常為JSON或者XML格式的數據。在服務器端和客戶端使用相同的數據結構很重要;
  • 使用Autorelease Pool:在某些循環創建臨時變量處理數據時,自動釋放池以保證能及時釋放內存;
  • 正確選擇圖片加載方式:詳情閱讀細讀UIImage加載方式
24.UIViewController的完整生命周期
-[ViewController initWithNibName:bundle:];
-[ViewController init];
-[ViewController loadView];
-[ViewController viewDidLoad];
-[ViewController viewWillDisappear:];
-[ViewController viewWillAppear:];
-[ViewController viewDidAppear:];
-[ViewController viewDidDisappear:];
25.UIImageView添加圓角
  • 最直接的方法就是使用如下屬性設置:
imgView.layer.cornerRadius = 10;
// 這一行代碼是很消耗性能的
imgView.clipsToBounds = YES;
  • 給UIImage添加生成圓角圖片的擴展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;
}

更多同類型文章請參考

iOS面試進階篇(一)
iOS面試進階篇(二)
iOS面試進階篇(三)
iOS面試進階篇(四)
iOS面試進階篇(五)


書寫整理多不容易,覺得寫的好的打賞一下吧。


更多相關類型文章敬請期待中

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。