iOS面試珠璣

iOS基礎類

這裏包含了去哪兒,滴滴,螞蟻金服,美團,今日頭條,快手以及其它公司的一些面試題,大部分面試官問的重複的問題不少,整體來講就是如下的面試題。面試

  1. 簡述iOS中的內存管理方式
  • iOS的內存管理用的是引用計數的方法,分爲MRC(手動引用計數)和ARC(自動引用計數)。算法

  • MRC:開發者手動地進行retain和release操做,對每一個對象的retainCount進行+1,-1操做,當retainCount爲0時,系統會自動釋放對象內存。數據庫

  • ARC:開發者經過聲明對象的屬性爲strong,weak,retain,assign來管理對象的引用計數,被strong和retain修飾的屬性變量系統會自動對所修飾變量的引用計數進行自增自減操做,一樣地,retainCount爲0時,系統會釋放對象內存。api


  1. block的分類,__block的做用,block循環引用產生的緣由及解決辦法
  • blcok分爲全局blcok,堆block,棧block。
  • 在 MRC下:只要沒有訪問外部變量,就是全局block。訪問了外部變量,就是棧block。顯示地調用[block copy]就是堆block。
  • 在 ARC下:只要沒有訪問外部變量,就是全局block。若是訪問了外部變量,那麼在訪問外部變量以前存儲在棧區,訪問外部變量以後存儲在堆區。
  • __block的做用:將外部變量的傳遞形式由值傳遞變爲指針傳遞,從而能夠獲取而且修改外部變量的值。一樣,外部變量的修改,也會影響block函數的輸出。
  • block循環引用問題:當一個類的對象持有block,block裏面又引用了這個對象,那麼就是一個循環引用的關係。能夠用strong-weak-dance的方法解除循環引用。

3.深拷貝與淺拷貝數組

  • 深拷貝就是開闢一塊新的內存空間來存儲原來內存空間的內容,對象指針指向新的內存空間。淺拷貝只是從新生成一個指針,指向的仍是原來的內存空間。xcode

  • copy方法:若是是非可擴展類對象,則是淺拷貝。若是是可擴展類對象,則是深拷貝。瀏覽器

  • mutableCopy方法:不管是可擴展類對象仍是不可擴展類對象,都是深拷貝。緩存

  • 注意:深拷貝和深複製不一樣,深拷貝的內存空間的元素仍是指向原地址,可是深複製會開闢新的內存空間從新複製子元素。安全


4.iOS中常見的屬性和默認的對象屬性服務器

  • 常見屬性: atomic, nonatomic, assign, retain, strong, weak, copy, readonly, readwrite, unsafe_unretained, getter=, setter= 等。

  • 默認屬性: 繼承於NSObject類的對象:(atomic, strong), 非繼承於NSObject類的對象:(atomic, assign)

  • 屬性意義:

    atomic:原子性的,在執行setter和getter方法時能夠保證訪問變量的線程安全。
    nonatomic:非原子性的,沒法保證訪問變量的線程安全性,可是變量訪問效率會提升。
    assign:主要用於修飾非繼承於NSObject類型的對象,例如int, double, NSInteger等,當該對象被其餘對象引用時,該對象的引用計數不會自加1。
    retain:通常狀況下等同於ARC環境下的strong修飾符,可是在修飾block對象時,retain至關於assign,而strong至關於copy。
    strong:主要用於繼承於NSObject類的對象,當strong修飾的對象被其餘對象引用時,引用計數會自加1。
    weak:主要用於繼承於NSObject類的對象,當weak修飾的對象被其餘對象引用時,引用計數不會自加1,且retainCount爲0時,指向該對象的指針將會置nil,指向堆棧的底部0x00000000,防止野指針的出現。
    unsafe_unretained:主要用於繼承於NSObject類型的對象,當retainCount爲0時,指向該對象的指針不會置nil,所以可能會出現野指針,可是效率方面會比weak要高。
    copy:主要適用於NSArray, NSDictionary, NSString, Block等類型的對象,開闢一塊新的內存存儲原來內存中的元素,對象指針指向新內存的地址。
    readonly: 只讀屬性
    readwrite: 讀寫屬性
    getter = : 修改讀屬性名稱
    setter = : 修改寫屬性名稱

5.哪些屬性須要聲明成copy,爲何?

  • NSDictionary, NSArray, NSString, Block須要聲明爲copy屬性修飾,block用copy修飾是由於block只有拷貝到堆上才能保證調用block的時候,block沒有被系統提早釋放掉。NSDictionary, NSArray, NSString用copy修飾的緣由直接上代碼(以NSString舉例)
@interface ViewController ()
@property (nonatomic, copy)NSString *aStr;
@property (nonatomic, strong)NSString *bStr;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
// [self buildUI];
    [self testCode];
}

- (void)testCode{
    
    NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"%@", @"abc"];
    self.aStr = mutableStr;
    self.bStr = mutableStr;
    [mutableStr appendString:@"123"];
    NSLog(@"copy修飾的字符串:%@", self.aStr);
    NSLog(@"strong修飾的字符串:%@", self.bStr);
}
複製代碼

打印結果:

2018-05-22 21:13:58.344883 TTFeedBackDemo[1224:245923] copy修飾的字符串:abc
2018-05-22 21:13:58.345004 TTFeedBackDemo[1224:245923] strong修飾的字符串:abc123
複製代碼

用了copy屬性修飾以後,能夠防止這些類型的對象被引用而且改變內容。


  1. 通知,代理,block,KVO的使用場景分別是什麼,有什麼區別?
  • 通知: 適用於毫無關聯的頁面之間或者系統消息的傳遞,屬於一對多的信息傳遞關係。例如系統音量的改變,系統狀態的改變,應用模式的設置和改變,都比較適合用通知去傳遞信息。

  • 代理: 一對一的信息傳遞方式,適用於相互關聯的頁面之間的信息傳遞,例如push和present出來的頁面和原頁面之間的信息傳遞。

  • block: 一對一的信息傳遞方式,效率會比代理要高(畢竟是直接取IMP指針的操做方式)。適用的場景和代理差很少,都是相互關聯頁面之間的頁面傳值。

  • KVO: 屬性監聽,監聽對象的某一屬性值的變化情況,當須要監聽對象屬性改變的時候使用。例如在UIScrollView中,監聽contentOffset,既能夠用KVO,也能夠用代理。可是其餘一些狀況,好比說UIWebView的加載進度,AVPlayer的播放進度,就只能用KVO來監聽了,不然獲取不到對應的屬性值。


  1. 簡述對OC中的isa指針的認識
  • isa指針:首先,貼出NSObject.h文件,你們宏觀感覺一下。

    Ojective-C語言是基於C語言的封裝,它實現了將面向過程的語言向面向對象的語言的轉變。而OC中絕大部分類又是繼承於NSObject類的,因此研究清楚NSObject類的構成,對於理解OC語言頗有幫助。

    NSObject類引入了兩個頭文件:#include <objc/objc.h>#include <objc/NSObjCRuntime.h>,第一個頭文件引入的是objc結構體的構成方式即isa指針,第二個頭文件引入的是Runtime消息查找機制。
    接下來又引入了三個類的聲明:@class NSString, NSMethodSignature, NSInvocation;
    NSMethodSignature和NSInvacation和OC的方法轉發機制有關,而NSString是與NSObject的+ (NSString *)description方法有關。

    isa指針: 代碼以下

    @interface NSObject <NSObject> {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
    #pragma clang diagnostic pop
    }
    複製代碼

    NSObject對象其實包含了一個Class類型的isa指針。 這個和id類型是同樣的,代碼以下:

    struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    
    /// A pointer to an instance of a class.
    typedef struct objc_object *id;
    複製代碼

    即id類型實際上是objc_object指針類型的別稱。objc_object結構體一樣也是包含了一個指向Class類型的指針。 繼續看一下,Class isa指針的內部結構,以下

    struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;//指向元類的Class指針
    
    #if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;//指向父類的Class指針
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;//類名
    long version                                             OBJC2_UNAVAILABLE;//類的版本信息,默認爲0
    long info                                                OBJC2_UNAVAILABLE;//運行期使用的一些位標識
    long instance_size                                       OBJC2_UNAVAILABLE;//該類的實例變量大小
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;//屬性列表
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;//方法列表
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;//緩存方法列表
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;//協議列表
    #endif
    
    } OBJC2_UNAVAILABLE;
    
    typedef struct objc_class *Class;
    複製代碼

    Class其實就是一個objc_class類型的結構體指針。objc_class的結構體變量構成見上圖,下面是objc_class類的super_class指針和isa元類指針的具體指向關係,請你們分清對象,對象的類,元類,根元類這些概念。


  1. 簡述OC中的消息轉發機制
  • 當objc_msgSend方法調用找不到響應的函數名稱時就會進行消息轉發,主要分爲3步:

    一、動態方法解析

    調用方法+(BOOL)resolveInstanceMethod:(SEL)sel(實例方法動態解析)和+ (BOOL)resolveClassMethod:(SEL)sel(類方法動態解析)。

    二、備援接收者

    調用方法 - (id)forwardingTargetForSelector:(SEL)aSelector

    三、徹底轉發

    調用方法- (void)forwardInvocation:(NSInvocation *)anInvocation- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

    具體的轉發流程見下圖:


  1. 響應鏈原理
  • 當用戶觸摸屏幕時,觸碰屏幕產生事件UIEvent並存入UIApplication中的事件隊列中, 而且在整個視圖結構中自上而下的進行分發,以下圖所示:

  • 這裏着重介紹兩個方法

//判斷當前點擊事件是否存在最優響應者(First Responder)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
複製代碼
//判斷當前點擊是否在控件的Bounds以內
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
複製代碼

第一個方法返回一個能夠響應event觸摸事件的UIView,第二個方法判斷觸摸點位在不在可相應範圍以內的BOOL值。因此會衍生出一些問題,好比說「如何讓一個父視圖之外的子視圖響應點擊事件」,「如何只讓一個UIView的圓形區域響應觸摸事件」等等,在此因爲篇幅限制,再也不一一展開詳述。下面這幅圖簡述了系統查找響應事件控件的流程。


  1. 手寫一個block結構體聲明
  • 這就是考察一名iOS開發人員的寫碼基本功了,你們加深印象便可: typedef void(^RBBlogDemoHandler)(void);

  1. RunLoop原理,RunLoop與線程的關係
  • RunLoop其實就是一個do-while循環,Runloop的存在保證了程序一直在前臺運行。RunLoop和線程是一一對應的關係,即開啓一個線程,就會建立一個RunLoop對線程進行處理和管理,直到Runloop中沒有須要處理的item,RunLoop纔會進入休眠狀態,若是休眠一段時間沒有被喚醒的話,RunLoop將會被銷燬掉。RunLoop的執行邏輯見下圖:

  1. GCD與NSOperation兩種管理多線程方式的異同點
  • GCD是用C語言實現的,而NSOperation是用OC實現的。
  • NSOperation能夠設置最大線程併發數,能夠設置線程依賴關係,能夠設置線程的優先級。
  • GCD方式管理多線程是一種對開發者很是友好的開發方式,開發者只須要關注同步異步,串行併發這些線程關係就能夠輕鬆地進行線程管理了。另外,線程中執行的任務是經過Block的形式調用的,因此執行效率也是很是高的。

  1. GCD的經常使用api
  • dispatch_sync:同步線程函數
  • dispatch_async:異步線程函數
  • dispatch_group_async:羣線程函數
  • dispatch_barrier_async:柵欄函數,阻塞所屬的隊列的線程
  • dispatch_barrier_sync:柵欄函數,阻塞當前線程
  • dispatch_apply:該函數按指定的次數將指定的Block追加到指定的Dispatch Queue中,並等待所有處理執行結束。

  1. GCD中的同步異步,串行併發的概念,GCD常見的線程死鎖問題
  • 同步:針對於線程而言的概念,阻塞當前線程,不執行結束,當前線程就不會繼續往下執行。
  • 異步:針對於線程而言的概念,不阻塞當前線程,當前線程會繼續往下執行。
  • 串行:針對於隊列而言,串行隊列遵照FIFO(first-in-first-out)原則,只能一個任務一個任務地順序執行。
  • 併發:針對於隊列而言,併發隊列能夠在同一時間執行多個任務。
  • 相似於
dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"%@", @"123");
    });
複製代碼

這樣的函數,就是典型的GCD死鎖函數。 由於dispatch_sync阻塞的當前的線程,而當前線程是main_queue,也就是說是一個串行線程,當前線程只有先執行NSLog(@"%@", @"123")才能繼續運行下去,可是當前線程又被阻塞掉了,沒法向下繼續執行,因此這就是一個死鎖的GCD執行函數了。


  1. iOS中經常使用的線程鎖有哪些,分別具備哪些特色?
  • @synchronized 關鍵字加鎖 互斥鎖,性能較差不推薦使用
  • NSLock 互斥鎖 不能屢次調用 lock方法,會形成死鎖
  • NSRecursiveLock遞歸鎖,NSRecursiveLock類定義的鎖能夠在同一線程屢次lock,而不會形成死鎖。遞歸鎖會跟蹤它被多少次lock。每次成功的lock都必須平衡調用unlock操做。只有全部的鎖住和解鎖操做都平衡的時候,鎖才真正被釋放給其餘線程得到。
  • NSConditionLock條件鎖,顧名思義,這個鎖對象有一個condition屬性,只有condition的值相同,才能獲取到該鎖,而且執行解鎖操做。
  • POSIX互斥鎖,POSIX是Unix/Linux平臺上提供的一套條件互斥鎖的API。用法和特色與NSLock相似。
  • dispatch_semaphore信號量實現加鎖,當信號量爲0時,線程將會被卡死,經過信號量的增減來達到控制線程個數的目的。
  • OSSpinLock自旋鎖,用法相似於NSLock,能夠自動檢查線程鎖是否已經打開,效率比較高,可是被證實不是線程安全的。
  • GCD線程阻斷dispatch_barrier_async/dispatch_barrier_syncdispatch_barrier_async/dispatch_barrier_sync在必定的基礎上也能夠作線程同步,會在線程隊列中打斷其餘線程執行當前任務。兩個的區別是dispatch_barrier_async阻塞的是當前隊列的線程,而dispatch_barrier_sync阻塞的是任務所插入隊列的線程。
  • 各類線程鎖的執行效率對好比下圖:

  1. Father的子類Son,分別寫出NSStringFromClass([self class]),NSStringFromClass([super class]),NSStringFromClass(self.superClass)的打印值
  • [self class] : Son
  • [super class] : Son
  • self.superClass : Father
  • 第一個就不用解釋了,打印本類的類名。
  • [super class]找到NSObject中class方法之後,reciever不變。其實是由於super只是一個「編譯器指示符」,它和self指向的是相同的receiver。這裏要深入理解super所指代的上下文環境。
  • self.superClass是取到了本類的superClass指針,因此打印的是父類的類名。

  1. KVO的原理
  • 例如,A類的實例的name屬性被B類的實例監聽了。這時,OC的runtime機制生成了一個KVONotifying_A的類來替代原來的A類,重寫了+ (Class)class方法,返回[A Class],從而把本身假裝成A類。重寫了A類屬性name的setter方法加入了NSObject的兩個方法:willChangeValueForKey:(值改變以前)和didChangevlueForKey:(值改變以後)。在一個被觀察屬性發生改變以前,willChangeValueForKey:必定會被調用,這就會記錄舊的值。而當改變發生後,didChangeValueForKey:會被調用,繼而observeValueForKey:ofObject:change:context:也會被調用。

  1. runtime的機制和應用
  • Objective-C是一門動態強類型語言,它會將一些工做放在代碼運行時才處理而並不是編譯時。也就是說,有不少類和成員變量在咱們編譯的時是不知道的,而在運行時,咱們所編寫的代碼會轉換成完整的肯定的代碼運行。所以,咱們還須要一個運行時系統(Runtime system)來處理編譯後的代碼。例如OC中的類對象,都是在程序的運行期才知道這個對象是哪一個類的對象,該類具備哪些特徵,等等。咱們執行的函數例如:[foo doSomeThing],實際上是經過函數objc_msgSend(foo, doSomeThing)來調用的,編譯器將會在foo類的方法樹中進行查找。
  • 具體的應用:JSON轉Model,Model轉數據庫語言,方法交換Method Swizzing,消息轉發,等等。

19.MJExtension, MJRefresh, SDWebImage的實現原理

  • MJExtension:經過運行時,拿到Model對應的PropertyName,而後經過KVC,將字典中的值傳入Model。
  • MJRefresh:全部的View繼承於父類MJRefreshComponent,經過監聽SCrollView的contentOffset來判斷Refresh狀態,從而觸發各類狀態的函數方法。
  • SDWebImage:SDWebImageManager拿到須要請求的URL,會進行三級緩存的查找:NSCache, Memery磁盤,服務器。SDWebImageDownLoader會下載圖片對應的Data,開啓CGRefImage上下文進行圖片異步渲染繪製獲得UIImage而後傳入UIImageView。

  1. NSTimer計時器是準確的嗎,爲何?
  • NSTimer計時器不是準確的。
  • 緣由:定時器被添加在主線程中,因爲定時器在一個RunLoop中被檢測一次,因此若是在這一次的RunLoop中作了耗時的操做,當前RunLoop持續的時間超過了定時器的間隔時間,那麼下一次定時就被延後了。

  1. 類的分類和類的擴展的區別,類的分類的實現原理。
  • 類的分類能夠動態添加方法(運行時),類的擴展能夠添加更多的屬性變量(編譯期)。  
  • 類的分類的實現原理:在運行時過程當中,本類的方法加載完畢以後,會查詢是否有類的分類,若是有類的分類,就會再去加載類的分類的方法,把這些方法所有存儲到objc_class結構體的methodLists數組中。注意,這裏的類的分類的方法是插入到數組的第一個元素位置的,也就是說類的分類的方法會覆蓋本類的同名方法。若是有多個類的分類都包含同名函數,那麼最後一個被加載進compile sources的類的分類文件中的方法將會覆蓋其餘的同名方法。

  1. iOS動態關聯屬性(objc_setAssociatedObject,objc_getAssocicatedObject)的實現原理
  • AssociationsManager 是頂級的對象,維護了一個從spinlock_t 鎖到AssociationsHashMap哈希表的單例鍵值對映射;
  • AssociationsHashMap是一個無序的哈希表,維護了從對象地址到 ObjectAssociationMap的映射;
  • ObjectAssociationMap 是一個 C 中的 map ,維護了從 key 到 ObjcAssociation 的映射,即關聯記錄;
  • ObjcAssociation是一個C的類,表示一個具體的關聯結構,主要包括兩個實例變量,_policy 表示關聯策略,_value 表示關聯對象。

  1. Masonry的抗壓縮屬性和抗拉伸屬性
  • 通常狀況下,用Masonry設置兩個平行的自適應Label(左面爲Label1,右面爲Label2),那麼效果圖應該以下:
  • 可是我想達到這樣的效果,應該怎麼設置呢?
  • 能夠設置抗拉伸屬性優先級,代碼以下:
[label1 setContentHuggingPriority:UILayoutPriorityRequired
                          forAxis:UILayoutConstraintAxisHorizontal];
[label2 setContentHuggingPriority:UILayoutPriorityDefaultLow
                          forAxis:UILayoutConstraintAxisHorizontal];
複製代碼
  • 當文字過多的時候,通常效果以下:
  • 那麼我想實現這樣的效果,應該怎麼辦呢?
  • 能夠設置抗壓縮屬性,代碼以下:
[label1 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
                                        forAxis:UILayoutConstraintAxisHorizontal];
[label2 setContentCompressionResistancePriority:UILayoutPriorityRequired
                                        forAxis:UILayoutConstraintAxisHorizontal];
複製代碼
  1. 加密的種類,對稱加密和非對稱加密
  • 加密種類:
  • 對稱加密算法:MD5,DES,AES。
  • 非對稱加密算法:RSA等加密方式。
  • 對稱加密:對稱加密是最快速、最簡單的一種加密方式,加密與解密用的是一樣的密鑰,這種方法在密碼學中叫作對稱加密算法。
  • 非對稱加密:非對稱加密爲數據的加密與解密提供了一個很是安全的方法,它使用了一對密鑰,公鑰和私鑰。私鑰只能由一方安全保管,不能外泄,而公鑰則能夠發給任何請求它的人。非對稱加密使用這對密鑰中的一個進行加密,而解密則須要另外一個密鑰。

  1. 解釋一下七層網絡結構,三次握手協議和四次揮手協議
  • 七層網絡協議:

    由低到高:物理層、數據鏈路層、網絡層、傳輸層、表示層、會話層、應用層。
  • 三次握手協議:

    第一次握手:創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
    第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
    第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP鏈接成功)狀態,完成三次握手。
  • 四次揮手協議:

    1.第一次揮手:主機1(可使客戶端,也能夠是服務器端),設置Sequence Number和Acknowledgment Number,向主機2發送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了;
    2.第二次揮手:主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段,Acknowledgment Number爲Sequence Number加1;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我也沒有數據要發送了,能夠進行關閉鏈接了;
    3.第三次揮手:主機2向主機1發送FIN報文段,請求關閉鏈接,同時主機2進入CLOSE_WAIT狀態;
    4.第四次揮手:主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段,而後主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段之後,就關閉鏈接;此時,主機1等待2MSL後依然沒有收到回覆,則證實Server端已正常關閉,那好,主機1也能夠關閉鏈接了。

  1. http和https的區別
  • https在http的基礎上增長了SSL數據傳輸安全性認證層。具體關係以下圖:
  • https協議須要到ca申請證書。http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。http和https使用的是徹底不一樣的鏈接方式用的端口也不同,前者是80,後者是443。http的鏈接很簡單,是無狀態的。HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議。

  1. https雙向驗證原理
  • 1.瀏覽器將本身支持的一套加密規則發送給網站。
  • 2.網站從中選出一組加密算法與HASH算法,並將本身的身份信息以證書的形式發回給瀏覽器。證書裏面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。
  • 3.瀏覽器得到網站證書以後瀏覽器要作如下工做:
    a) 驗證證書的合法性(頒發證書的機構是否合法,證書中包含的網站地址是否與正在訪問的地址一致等),若是證書受信任,則瀏覽器欄裏面會顯示一個小鎖頭,不然會給出證書不受信的提示。
    b) 若是證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,並用證書中提供的公鑰加密。
    c) 使用約定好的HASH算法計算握手消息,並使用生成的隨機數對消息進行加密,最後將以前生成的全部信息發送給網站。
  • 4.網站接收瀏覽器發來的數據以後要作如下的操做:
    a) 使用本身的私鑰將信息解密取出密碼,使用密碼解密瀏覽器發來的握手消息,並驗證HASH是否與瀏覽器發來的一致。
    b) 使用密碼加密一段握手消息,發送給瀏覽器。
  • 5.瀏覽器解密並計算握手消息的HASH,若是與服務端發來的HASH一致,此時握手過程結束,以後全部的通訊數據將由以前瀏覽器生成的隨機密碼並利用對稱加密算法進行加密。
  • 具體的流程見下圖:


  1. HTTP經常使用的頭部字段,常見的返回狀態碼和意義
  • 常見的頭部字段:

    host頭域
    Host頭域指定請求資源的Intenet主機和端口號,必須表示請求url的原始服務器或網關的位置。HTTP/1.1請求必須包含主機頭域,不然系統會以400狀態碼返回。
    Referer頭域
    Referer頭域容許客戶端指定請求uri的源資源地址,這能夠容許服務器生成回退鏈表,可用來登錄、優化cache等。他也容許廢除的或錯誤的鏈接因爲維護的目的被追蹤。若是請求的uri沒有本身的uri地址,Referer不能被髮送。若是指定的是部分uri地址,則此地址應該是一個相對地址。
    User-Agent頭域
    User-Agent頭域的內容包含發出請求的用戶信息,User Agent也簡稱UA。用較爲普通的一點來講,是一種向訪問網站提供你所使用的瀏覽器類型、操做系統及版本、CPU類型、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等信息的標識。
    Cache-Control頭域
    Cache-Control指定請求和響應遵循的緩存機制。在請求消息或響應消息中設置Cache-Control並不會修改另外一個消息處理過程當中的緩存處理過程。請求時的緩存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,響應消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。
    Date頭域
    Date頭域表示消息發送的時間,時間的描述格式由rfc822定義。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的時間表示世界標準時,換算成本地時間,須要知道用戶所在的時區。
  • 返回的狀態碼:

    200(成功) 服務器已成功處理了請求。一般,這表示服務器提供了請求的網頁。
    201(已建立) 請求成功且服務器已建立了新的資源。
    202(已接受) 服務器已接受了請求,但還沒有對其進行處理。
    203(非受權信息) 服務器已成功處理了請求,但返回了可能來自另外一來源的信息。
    204(無內容) 服務器成功處理了請求,但未返回任何內容。
    205(重置內容) 服務器成功處理了請求,但未返回任何內容。與 204 響應不一樣,此響應要求請求者重置文檔視圖(例如清除表單內容以輸入新內容)。
    206(部份內容) 服務器成功處理了部分 GET 請求。
    300(多種選擇) 服務器根據請求可執行多種操做。服務器可根據請求者 來選擇一項操做,或提供操做列表供其選擇。
    301(永久移動) 請求的網頁已被永久移動到新位置。服務器返回此響應時,會自動將請求者轉到新位置。您應使用此代碼通知搜索引擎蜘蛛網頁或網站已被永久移動到新位置。
    302(臨時移動) 服務器目前正從不一樣位置的網頁響應請求,但請求者應繼續使用原有位置來進行之後的請求。會自動將請求者轉到不一樣的位置。但因爲搜索引擎會繼續抓取原有位置並將其編入索引,所以您不該使用此代碼來告訴搜索引擎頁面或網站已被移動。
    303(查看其餘位置) 當請求者應對不一樣的位置進行單獨的 GET 請求以檢索響應時,服務器會返回此代碼。對於除 HEAD ##### 304(未修改) 自從上次請求後,請求的網頁未被修改過。服務器返回此響應時,不會返回網頁內容。若是網頁自請求者上次請求後再也沒有更改過,您應當將服務器配置爲返回此響應。因爲服務器能夠告訴 搜索引擎自從上次抓取後網頁沒有更改過,所以可節省帶寬和開銷。
    305(使用代理) 請求者只能使用代理訪問請求的網頁。若是服務器返回此響應,那麼,服務器還會指明請求者應當使用的代理。
    307(臨時重定向) 服務器目前正從不一樣位置的網頁響應請求,但請求者應繼續使用原有位置來進行之後的請求。會自動將請求者轉到不一樣的位置。但因爲搜索引擎會繼續抓取原有位置並將其編入索引,所以您不該使用此代碼來告訴搜索引擎某個頁面或網站已被移動。
    400(錯誤請求) 服務器不理解請求的語法。
    401(身份驗證錯誤) 此頁要求受權。您可能不但願將此網頁歸入索引。
    403(禁止) 服務器拒絕請求。
    404(未找到) 服務器找不到請求的網頁。例如,對於服務器上不存在的網頁常常會返回此代碼。例如:www.0631abc.com/20100aaaa,就…
    405(方法禁用) 禁用請求中指定的方法。
    406(不接受) 沒法使用請求的內容特性響應請求的網頁。
    407(須要代理受權) 此狀態碼與 401 相似,但指定請求者必須受權使用代理。若是服務器返回此響應,還表示請求者應當使用代理。
    408(請求超時) 服務器等候請求時發生超時。
    409(衝突) 服務器在完成請求時發生衝突。服務器必須在響應中包含有關衝突的信息。服務器在響應與前一個請求相沖突的 PUT 請求時可能會返回此代碼,以及兩個請求的差別列表。
    410(已刪除) 請求的資源永久刪除後,服務器返回此響應。該代碼與 404(未找到)代碼類似,但在資源之前存在而如今不存在的狀況下,有時會用來替代 404 代碼。若是資源已永久刪除,您應當使用 301 指定資源的新位置。
    411(須要有效長度) 服務器不接受不含有效內容長度標頭字段的請求。
    412(未知足前提條件) 服務器未知足請求者在請求中設置的其中一個前提條件。
    413(請求實體過大) 服務器沒法處理請求,由於請求實體過大,超出服務器的處理能力。
    414(請求的 URI 過長) 請求的 URI(一般爲網址)過長,服務器沒法處理。
    415(不支持的媒體類型) 請求的格式不受請求頁面的支持。
    416(請求範圍不符合要求) 若是頁面沒法提供請求的範圍,則服務器會返回此狀態碼。
    417(未知足指望值) 服務器未知足"指望"請求標頭字段的要求。
    500(服務器內部錯誤) 服務器遇到錯誤,沒法完成請求。
    501(還沒有實施) 服務器不具有完成請求的功能。例如,當服務器沒法識別請求方法時,服務器可能會返回此代碼。
    502(錯誤網關) 服務器做爲網關或代理,從上游服務器收到了無效的響應。
    503(服務不可用) 目前沒法使用服務器(因爲超載或進行停機維護)。一般,這只是一種暫時的狀態。
    504(網關超時) 服務器做爲網關或代理,未及時從上游服務器接收請求。
    505(HTTP 版本不受支持) 服務器不支持請求中所使用的 HTTP 協議版本。

  1. @class和import以及include的區別
  • import會引入整個.h頭文件。
  • @class只是告訴編譯器該類中可使用這個class類名。
  • include和import的做用相似,可是可能形成重複引用的問題,通常用判斷宏定義是否存在的方式來防止循環引用。

  1. weak對象的管理方式
  • weak是弱引用,所引用對象的計數器不會加一,並在引用對象被釋放的時候自動被設置爲nil。runtime維護了一個weak表,用於存儲指向某個對象的全部weak指針。weak表實際上是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象的地址)數組。

  • 一、初始化時:runtime會調用objc_initWeak函數,初始化一個新的weak指針指向對象的地址。

  • 二、添加引用時:objc_initWeak函數會調用 objc_storeWeak() 函數, objc_storeWeak() 的做用是更新指針指向,建立對應的弱引用表。

  • 三、釋放時,調用clearDeallocating函數。clearDeallocating函數首先根據對象地址獲取全部weak指針地址的數組,而後遍歷這個數組把其中的數據設爲nil,最後把這個entry從weak表中刪除,最後清理對象的記錄。


  1. iOS的retain和release的操做是在編譯期仍是運行時進行的
  • retain和release是在編譯期由編譯器自動生成的代碼,例如:
- (void) setUserName:(UITextField *)userName { 
    [_userName release]; 
    _userName = [userName retain]; 
}
複製代碼

  1. +(void)load方法和+(void)initial方法的異同
  • +(void)load方法:
  • 對於加入運行期系統的類及分類,一定會調用此方法,且僅調用一次。 iOS會在應用程序啓動的時候調用load方法,在main函數以前調用 執行子類的load方法前,會先執行全部超類的load方法,順序爲父類->子類->分類 在load方法中使用其餘類是不安全的,由於會調用其餘類的load方法,而若是關係複雜的話,就沒法判斷出各個類的載入順序,類只有初始化完成後,類實例才能進行正常使用 load 方法不聽從繼承規則,若是類自己沒有實現load方法,那麼系統就不會調用,無論父類有沒有實現(跟下文的initialize有明顯區別) 儘量的精簡load方法,由於整個應用程序在執行load方法時會阻塞,即,程序會阻塞直到全部類的load方法執行完畢,纔會繼續 load 方法中最經常使用的就是方法交換method swizzling。
  • +(void)initial方法:
  • 在首次使用該類以前由運行期系統調用,且僅調用一次 惰性調用,只有當程序使用相關類時,纔會調用 運行期系統會確保initialize方法是在線程安全的環境中執行,即,只有執行initialize的那個線程能夠操做類或類實例。其餘線程都要先阻塞,等待initialize執行完。若是類未實現initialize方法,而其超類實現了,那麼會運行超類的實現代碼,並且會運行兩次。initialize方法是線程安全的,能夠用來設置內部數據,好比,某個全局狀態,如數組、字典等沒法在編譯期初始化,能夠放在initialize裏面。

  1. UIViewController的生命週期方法調用順序
  • 當一個視圖控制器被建立,並在屏幕上現實的時候。代碼的執行順序:

    1.alloc       建立對象,分配空間。
    2.init       初始化對象,初始化數據。
    3.loadView    從nib載入視圖,一般這一步不須要去幹涉。除非你沒有使用xib文件建立視圖
    4.viewDidLoad   載入完成,能夠進行自定義數據以及動態的建立其餘空間。
    5.viewWillAppear  視圖將出如今屏幕以前。
    6.viewDidAppear  視圖在屏幕上渲染完成。
  • 當一個視圖被移除屏幕而且銷燬的時候執行順序:

    1.viewWillDisappear  視圖被移除以前。
    2.viewDidDisappear   視圖被移除以後。
    3.dealloc        銷燬視圖。

  1. iOS中各種控件的繼承樹關係
  • 一張圖告訴你全部的繼承關係:

  1. 如何化解NSTimer的循環引用關係
  • 首先要理解NSTimer爲何會引發循環引用:NSTimer和使用Timer的ViewController相互持有。
  • 解決辦法有兩個:
    1. 在ViewContoller的viewWillDisappear生命週期中註銷Timer。
    2. 引入第三方NSObject(如HWWeakTimer)管理和持有Timer,讓Timer持有第三方的成員變量。這樣就打破了互相引用的循環關係。

  1. 怎樣管理第三方SDK,CocoaPods和Carthage的異同
  • iOS中通常使用CocoaPods和Carthage來管理第三方SDK。

  • 二者的比較:

    1. Carthage只支持iOS 8及以上版本使用。
    2. CocoaPods默認會自動建立並更新你的應用程序和全部依賴的Xcode workspace。Carthage使用xcodebuild來編譯框架的二進制文件,但如何集成它們將交由用戶本身判斷。CocoaPods的方法更易於使用,但Carthage更靈活而且是非侵入性的。
    咱們建立Carthage的緣由是想要一種儘量簡單的工具——一個只關心本職工做的依賴管理器,而不是取代部分Xcode的功能,或者須要讓框架做者作一些額外的工做。CocoaPods提供的一些特性很棒,但因爲附加的複雜性,它們將不會被包含在Carthage當中。

  1. -(BOOL)isKindOfClass和-(BOOL)isMemberOfClass的區別
  • -(BOOL) isKindOfClass: classObj 判斷是不是這個類或者這個類的子類的實例

  • -(BOOL) isMemberOfClass: classObj 判斷是不是這個類的實例


  1. 數據持久化的幾種方式和對應的應用場景
  • plist文件(屬性列表):即直接拖拽plist文件到程序目錄當中。由NSBundle獲取本地plist資源。存儲一些本地的,且不會改變的數據到程序當中。
  • preference(偏好設置):即NSUserDefaults,存儲一些小型數據,設置參數,開關屬性等等。
  • NSKeyedArchiver(歸檔):存儲一些不涉及增刪改查的字典數組或者NSObject等,存儲的對象必定要遵循NSCoder和NSDecoder協議。
  • SQLite 3:存儲一些涉及增刪改查的字段數據。
  • CoreData:效率比較高,存儲一些涉及增刪改查的且體積很是大的數據。

  1. 如何實現一個完整的單例
  • 實現了單例的初始化以後,必定要重寫+(id) allocWithZone:(struct _NSZone *)zone,-(id) copyWithZone:(NSZone *)zone,-(id) mutablecopyWithZone:(NSZone *)zone這三個方法,代碼以下:
#import "Singleton.h"
@interface Singleton()<NSCopying,NSMutableCopying>
@end
 
@implementation Singleton
 
static Singleton* _instance = nil;
 
+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init] ;
        //不是使用alloc方法,而是調用[[super allocWithZone:NULL] init] 
        //已經重載allocWithZone基本的對象分配方法,因此要借用父類(NSObject)的功能來幫助出處理底層內存分配的雜物
    }) ;
     
    return _instance ;
}
 
+(id) allocWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}
 
-(id) copyWithZone:(NSZone *)zone
{
    return [Singleton shareInstance] ;//return _instance;
}
 
-(id) mutablecopyWithZone:(NSZone *)zone
{
    return [Singleton shareInstance] ;
}
@end
複製代碼

  1. iOS的系統單例有哪些?
  • [UIScreen mainScreen] (應用程序窗口)

  • [UIDevice currentDevice] (當前設備)

  • [UIApplication sharedApplication] (應用程序實例)

  • [NSNotificationCenter defaultCenter] (消息中心):

  • [NSFileManager defaultManager] (文件管理):

  • [NSUserDefaults standardUserDefaults] (應用程序設置):

  • [NSURLCache sharedURLCache] (請求緩存):

  • [NSHTTPCookieStorage sharedHTTPCookieStorage] (應用程序cookies池)


  1. APP啓動主要流程
  • APP啓動主要流程: 點擊icon -> 加載動態連接庫等 -> 映像文件加載imageLoader -> runtime -> load -> main -> delegate。

  1. iOS的沙盒機制
  • 出於安全考慮,iPhone對於安裝在上面的應用程序有所限制,這個限制就是應用程序只能在爲該改程序建立的文件系統中讀取文件,不能夠去其它地方訪問,此區域被成爲沙盒,因此全部的非代碼文件都要保存在此,例如圖像,圖標,聲音,映像,屬性列表,文本文件等。整體來講沙盒就是一種獨立、安全、封閉的空間。沙盒(sandbox)的核心內容是:sandbox對應用程序執行各類操做的權限限制。

  • 沙盒的特色:

    1. 每一個應用程序都有本身的存儲空間。
    2. 每一個應用程序都不能夠翻過本身的圍牆去訪問別的存儲空間的內容。(已經越獄的除外)
    3. 在訪問別人沙盒內的數據時須要訪問權限。
  • 應用程序沙盒目錄下有三個文件夾Documents、Library(下面有Caches和Preferences目錄)、tmp。

    Documents:保存應用運行時生成的須要持久化的數據iTunes會自動備份該目錄。蘋果建議將在應用程序中瀏覽到的文件數據保存在該目錄下。
    Library/Caches:通常存儲的是緩存文件,例如圖片視頻等,此目錄下的文件不會再應用程序退出時刪除,在手機備份的時候,iTunes不會備份該目錄。
    Library/Preferences:保存應用程序的全部偏好設置iOS的Settings(設置),咱們不該該直接在這裏建立文件,而是須要經過NSUserDefault這個類來訪問應用程序的偏好設置。iTunes會自動備份該文件目錄下的內容。
    tmp:臨時文件目錄,在程序從新運行的時候,和開機的時候,會清空tmp文件夾。

以上是Fabric本身總結的一些面試心經,有興趣的朋友能夠加我微信共同討論:justlikeitRobert。各位老鐵看了我這篇文章以後,若是找到了滿意的工做,別忘了和Fabric一塊兒分享成功喜悅,一分也是愛,哈哈!

相關文章
相關標籤/搜索