2019面試題(上)

一.設計模式是什麼? 你知道哪些設計模式,並簡要敘述?

設計模式是一種編碼經驗,就是用比較成熟的邏輯去處理某一種類型的事情。設計模式

  1. MVC模式:Model View Control,把模型 視圖 控制器 層進行解耦合編寫。
  2. MVVM模式:Model View ViewModel 把模型 視圖 業務邏輯 層進行解耦和編寫。
  3. 單例模式:經過static關鍵詞,聲明全局變量。在整個進程運行期間只會被賦值一次。
  4. 觀察者模式:KVO是典型的通知模式,觀察某個屬性的狀態,狀態發生變化時通知觀察者。
  5. 委託模式:代理+協議的組合。實現1對1的反向傳值操做。
  6. 工廠模式:經過一個類方法,批量的根據已有模板生產對象。

MVC 和 MVVM 的區別數組

在MVC下,Controller基本是沒法測試的,裏面混雜了個各類邏輯,並且分散在不一樣的地方。有了MVVM咱們就能夠測試裏面的viewModel,來驗證咱們的處理結果對不對(Xcode7的測試已經愈來愈完善了)。安全

好比iOS裏面有iPhone版本和iPad版本,除了交互展現不同外,業務邏輯的model是一致的。這樣,咱們就能夠以很小的代價去開發另外一個app。bash

MVVM是MVC的一個升級版,目前的MVC也能夠很快的轉換到MVVM這個模式。VC能夠省去一大部分展現邏輯。微信

缺點:網絡

每一個VC都附帶一個viewModel,類的數量*2多線程

咱們把邏輯給了viewModel,那勢必Model也會變得很複雜,裏面的屬性和方法愈來愈多。可能重寫的方法比較多,由於涉及到一些數據的轉換以及和controller之間的通訊。app

因爲數據都是從viewModel來,想一想忽然來了一個新人,一看代碼,不知道真實的模型是誰。好比經常使用tableview的數據源,通常都是一個數組,若是不斷的經過viewModel去取,溝通上沒有那麼直接。何況每封一層,意味着要寫不少代碼去融合他們的轉換。oop

Model負責存儲、定義、操做數據;性能

View用來展現給用戶,而且和用戶進行交互;

Controller是Model和View的協調者,Controller把Model中的數據拿過來給View使用。Controller能夠直接與Model和View進行通訊,而View不能與Controller直接通訊。,當有數據更新時,Model也要與Controller進行通訊,這個時候就要用Notification和KVO,這個方式就像發廣播同樣,Model發信號,Controller設置接收監聽信號,當有數據更新是就發信號給Controller,Model和View不能直接通訊,這樣違背MVC設計原則。View與Controller通訊須要利用代理協議的方式,Controller能夠直接根據Model決定View的展現。View若是接受響應事件則經過delegate,target-action,block等方式告訴Controller的狀態變化。Controller進行業務的處理,而後再控制View的展現。

關於MVVM的優勢:

  • 方便測試

  • 便於代碼的移植

  • 兼容MVC

  • 類會增多

  • viewModel會愈來愈龐大

  • 調用複雜度增長

二.#import跟 #include 有什麼區別,@class呢,#import<> 跟 #import」」有什麼區別?

(1)#import指令是Object-C針對@include的改進版本,能確保引用的文件只會被引用一次,不會陷入遞歸包含的問題中;

(2)@import與@class的區別:

#import會鏈入該頭文件的所有信息,包括實體變量和方法等;二@class只是告訴編譯器,其後面聲明的名稱是類的名稱,至於這些類如何定義的,暫時不用考慮。在頭文件中,通常只須要知道被引用的類的名稱就能夠了,不須要知道其內部的實體變量和方法,因此在頭文件中通常使用@class來聲明這個名稱是類的名稱;而在實現類裏面,由於會用到這個引用類的內部的實體變量和方法,因此須要使用#import類包含這個被引用類的頭文件。

@class還能夠解決循環包含的問題

(3)#import<>跟#import""的區別:

#import<>用來包含系統自帶的文件,#import""用來包含自定義的文件

(4)屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什麼做用,在那種狀況下用?

  • readwrite:是可讀可寫特性,同時生成get方法和set方法的聲明和實現(補充:默認屬性,將生成不帶額外參數的getter和setter方法(setterff只有一個參數))
  • readonly:只讀特性,只會生成get方法的聲明和實現;不但願屬性在類外改變
  • assign:是賦值特性,set方法的實現是直接賦值,用於基本數據類型;僅設置變量時
  • retain:表示持有特性,set方法將傳入參數先保留,再賦值,傳入參數的retaincount會+1;
  • copy:表示拷貝特性,set方法的實現是release舊值,copy新值,用於NSString、block等類型(set方法將傳入的對象複製一份;須要徹底一份新的變量時使用);
  • nonatomic:非原子操做,決定編譯器生成的setter getter是不是原子操做,atomic表示多線程安全,通常使用nonatomic

三.frame 和 bounds 有什麼不一樣?

frame指的是:該view在父view座標系統中的位置和大小。(參照點是父view的座標系統)

bounds指的是:該view在自己座標系統中的位置和大小。(參照點是自己座標系統)

四.Objective-C的類能夠多重繼承麼?能夠實現多個接口麼?Category是什麼?重寫一個類的方式用繼承好仍是分類好?爲何?

答:Objective-C的類不能夠多重繼承;能夠實現多個接口(協議);Category是類別;通常狀況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其餘類與原有類的關係。

五.@property 的本質是什麼?ivar、getter、setter 是如何生成並添加到這個類中的

@property 的本質是什麼?

@property = ivar + getter + setter;「屬性」

(property)有兩大概念:ivar(實例變量)、getter+setter(存取方法)

「屬性」 (property)做爲 Objective-C 的一項特性,主要的做用就在於封裝對象中的數據。 Objective-C 對象一般會把其所須要的數據保存爲各類實例變量。實例變量通常經過「存取方法」(access method)來訪問。其中,「獲取方法」 (getter)用於讀取變量值,而「設置方法」 (setter)用於寫入變量值。

六.@property中有哪些屬性關鍵字?/ @property 後面能夠有哪些修飾符?

屬性能夠擁有的特質分爲四類:

  1. 原子性--- nonatomic 特質
  2. 讀/寫權限---readwrite(讀寫)、readonly (只讀)
  3. 內存管理語義---assign、strong、 weak、unsafe_unretained、copy
  4. 方法名---getter= 、setter=
  5. 不經常使用的:nonnull,null_resettable,nullable

七.屬性關鍵字 readwrite,readonly,assign,retain,copy,nonatomic 各是什麼做用,在那種狀況下用?

答:

  1. readwrite 是可讀可寫特性。須要生成getter方法和setter方法。
  2. readonly 是隻讀特性。只會生成getter方法,不會生成setter方法,不但願屬性在類外改變。
  3. assign 是賦值特性。setter方法將傳入參數賦值給實例變量;僅設置變量時,assign用於基本數據類型。
  4. retain(MRC)/strong(ARC) 表示持有特性。setter方法將傳入參數先保留,再賦值,傳入參數的retaincount會+1。
  5. copy 表示拷貝特性。setter方法將傳入對象複製一份,須要徹底一份新的變量時。
  6. nonatomic 非原子操做。決定編譯器生成的setter和getter方法是不是原子操做,atomic表示多線程安全,通常使用nonatomic,效率高。

八.什麼狀況使用 weak 關鍵字,相比 assign 有什麼不一樣?

  1. 在 ARC 中,在有可能出現循環引用的時候,每每要經過讓其中一端使用 weak 來解決,好比: delegate 代理屬性。
  2. 自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak,自定義 IBOutlet 控件屬性通常也使用 weak;固然,也可使用strong。

IBOutlet連出來的視圖屬性爲何能夠被設置成weak?

由於父控件的subViews數組已經對它有一個強引用。

不一樣點:

assign 能夠用非 OC 對象,而 weak 必須用於 OC 對象。

weak 代表該屬性定義了一種「非擁有關係」。在屬性所指的對象銷燬時,屬性值會自動清空(nil)。

九.怎麼用 copy 關鍵字?

用途:

  1. NSString、NSArray、NSDictionary 等等常用copy關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary;

  2. block 也常用 copy 關鍵字。

說明:

block 使用 copy 是從 MRC 遺留下來的「傳統」,在 MRC 中,方法內部的 block 是在棧區的,使用 copy 能夠把它放到堆區.在 ARC 中寫不寫都行:對於 block 使用 copy 仍是 strong 效果是同樣的,但寫上 copy 也無傷大雅,還能時刻提醒咱們:編譯器自動對 block 進行了 copy 操做。若是不寫 copy ,該類的調用者有可能會忘記或者根本不知道「編譯器會自動對 block 進行了 copy 操做」,他們有可能會在調用以前自行拷貝屬性值。這種操做多餘而低效。

十.用@property聲明的 NSString / NSArray / NSDictionary 常用 copy 關鍵字,爲何?若是改用strong關鍵字,可能形成什麼問題?

答:用 @property 聲明 NSString、NSArray、NSDictionary 常用 copy 關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操做(就是把可變的賦值給不可變的),爲確保對象中的字符串值不會無心間變更,應該在設置新屬性值時拷貝一份。

  1. 由於父類指針能夠指向子類對象,使用 copy 的目的是爲了讓本對象的屬性不受外界影響,使用 copy 不管給我傳入是一個可變對象仍是不可對象,我自己持有的就是一個不可變的副本。
  2. 若是咱們使用是 strong ,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象在外部被修改了,那麼會影響該屬性。

//總結:使用copy的目的是,防止把可變類型的對象賦值給不可變類型的對象時,可變類型對象的值發送變化會無心間篡改不可變類型對象原來的值。

十一.淺拷貝和深拷貝的區別?

答:

淺拷貝:只複製指向對象的指針,而不復制引用對象自己。

深拷貝:複製引用對象自己。內存中存在了兩份獨立對象自己,當修改A時,A_copy不變。

十二.這個寫法會出什麼問題:@property (nonatomic, copy) NSMutableArray *arr;

問題:添加,刪除,修改數組內的元素的時候,程序會由於找不到對應的方法而崩潰。

緣由:是由於 copy 就是複製一個不可變 NSArray 的對象,不能對 NSArray 對象進行添加/修改。

十三.如何讓本身的類用 copy 修飾符?如何重寫帶 copy 關鍵字的 setter?

若想令本身所寫的對象具備拷貝功能,則需實現 NSCopying 協議。若是自定義的對象分爲可變版本與不可變版本,那麼就要同時實現 NSCopying 與 NSMutableCopying 協議。

具體步驟:

  1. 需聲明該類聽從 NSCopying 協議

  2. 實現 NSCopying 協議的方法。

十四.@synthesize 和 @dynamic 分別有什麼做用?

@property有兩個對應的詞,一個是@synthesize(合成實例變量),一個是@dynamic。

若是@synthesize和@dynamic都沒有寫,那麼默認的就是 @synthesize var = _var;

// 在類的實現代碼裏經過 @synthesize 語法能夠來指定實例變量的名字。(@synthesize var = _newVar;)

  1. @synthesize 的語義是若是你沒有手動實現setter方法和getter方法,那麼編譯器會自動爲你加上這兩個方法。

  2. @dynamic 告訴編譯器,屬性的setter與getter方法由用戶本身實現,不自動生成(如,@dynamic var)。

十五.常見的 Objective-C 的數據類型有那些,和C的基本數據類型有什麼區別?如:NSInteger和int

答:

Objective-C的數據類型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,這些都是class,建立後即是對象,而C語言的基本數據類型int,只是必定字節的內存空間,用於存放數值;NSInteger是基本數據類型,並非NSNumber的子類,固然也不是NSObject的子類。NSInteger是基本數據類型Int或者Long的別名(NSInteger的定義typedef long NSInteger),它的區別在於,NSInteger會根據系統是32位仍是64位來決定是自己是int仍是long。

十六.id 聲明的對象有什麼特性?

答:id 聲明的對象具備運行時的特性,便可以指向任意類型的Objcetive-C的對象。

十七.Objective-C 如何對內存管理的,說說你的見解和解決方法?

答:Objective-C的內存管理主要有三種方式ARC(自動內存計數)、手動內存計數、內存池。

  1. 自動內存計數ARC:由Xcode自動在App編譯階段,在代碼中添加內存管理代碼。
  2. 手動內存計數MRC:遵循內存誰申請、誰釋放;誰添加,誰釋放的原則。
  3. 內存釋放池Release Pool:把須要釋放的內存統一放在一個池子中,當池子被抽乾後(drain),池子中全部的內存空間也被自動釋放掉。內存池的釋放操做分爲自動和手動。自動釋放受runloop機制影響。

十八.Objective-C 中建立線程的方法是什麼?若是在主線程中執行代碼,方法是什麼?若是想延時執行代碼、方法又是什麼?

答:線程建立有三種方法:使用NSThread建立、使用GCD的dispatch、使用子類化的NSOperation,而後將其加入NSOperationQueue;在主線程執行代碼,方法是performSelectorOnMainThread,若是想延時執行代碼能夠用performSelector:onThread:withObject:waitUntilDone:

十九.Category(類別)、 Extension(擴展)和繼承的區別

區別:

  1. 分類有名字,類擴展沒有分類名字,是一種特殊的分類。

  2. 分類只能擴展方法(屬性僅僅是聲明,並沒真正實現),類擴展能夠擴展屬性、成員變量和方法。

  3. 繼承能夠增長,修改或者刪除方法,而且能夠增長屬性。

二十.咱們說的OC是動態運行時語言是什麼意思?

答:主要是將數據類型的肯定由編譯時,推遲到了運行時。簡單來講, 運行時機制使咱們直到運行時纔去決定一個對象的類別,以及調用該類別對象指定方法。

二十一.爲何咱們常見的delegate屬性都用是week而不是retain/strong?

答:是爲了防止delegate兩端產生沒必要要的循環引用。

@property (nonatomic, weak) id delegate;

二十二。何時用delete,何時用Notification?

Delegate(委託模式):1對1的反向消息通知功能。

Notification(通知模式):只想要把消息發送出去,告知某些狀態的變化。可是並不關心誰想要知道這個。

二十三.什麼是 KVO 和 KVC?

  1. KVC(Key-Value-Coding):鍵值編碼 是一種經過字符串間接訪問對象的方式(即給屬性賦值)

    舉例說明:

stu.name = @"張三" // 點語法給屬性賦值 
    
    [stu setValue:@"張三" forKey:@"name"]; // 經過字符串使用KVC方式給屬性賦值
    
    stu1.nameLabel.text = @"張三";
    
    [stu1 setValue:@"張三" forKey:@"nameLabel.text"]; // 跨層賦值
複製代碼
  1. KVO(key-Value-Observing):鍵值觀察機制 他提供了觀察某一屬性變化的方法,極大的簡化了代碼。

    KVO只能被KVC觸發,包括使用setValue:forKey:方法和點語法。

// 經過下方方法爲屬性添加KVO觀察
- (void)addObserver:(NSObject *)observer
                    forKeyPath:(NSString *)keyPath
                    options:(NSKeyValueObservingOptions)options
                    context:(nullable void *)context;
// 當被觀察的屬性發送變化時,會自動觸發下方方法
- (void)observeValueForKeyPath:(NSString *)keyPath
                    ofObject:(id)object
                    change:(NSDictionary *)change
                    context:(void *)context{}

複製代碼

KVC 和 KVO 的 keyPath 能夠是屬性、實例變量、成員變量。

二十四.KVC的底層實現?

當一個對象調用setValue方法時,方法內部會作如下操做:

  1. 檢查是否存在相應的key的set方法,若是存在,就調用set方法。
  2. 若是set方法不存在,就會查找與key相同名稱而且帶下劃線的成員變量,若是有,則直接給成員變量屬性賦值。
  3. 若是沒有找到_key,就會查找相同名稱的屬性key,若是有就直接賦值。
  4. 若是尚未找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法。

這些方法的默認實現都是拋出異常,咱們能夠根據須要重寫它們。

二十五.ViewController生命週期

按照執行順序排列:

  1. initWithCoder:經過nib文件初始化時觸發。
  2. awakeFromNib:nib文件被加載的時候,會發生一個awakeFromNib的消息到nib文件中的每一個對象。
  3. loadView:開始加載視圖控制器自帶的view。
  4. viewDidLoad:視圖控制器的view被加載完成。
  5. viewWillAppear:視圖控制器的view將要顯示在window上。
  6. updateViewConstraints:視圖控制器的view開始更新AutoLayout約束。
  7. viewWillLayoutSubviews:視圖控制器的view將要更新內容視圖的位置。
  8. viewDidLayoutSubviews:視圖控制器的view已經更新視圖的位置。
  9. viewDidAppear:視圖控制器的view已經展現到window上。
  10. viewWillDisappear:視圖控制器的view將要從window上消失。
  11. viewDidDisappear:視圖控制器的view已經從window上消失。

二十六.你是否接觸過OC中的反射機制?簡單聊一下概念和使用

  1. class反射

    經過類名的字符串形式實例化對象。

    Class class = NSClassFromString(@"student");
    Student *stu = [[class alloc] init];
    複製代碼

    將類名變爲字符串。

    Class class =[Student class];
    NSString *className = NSStringFromClass(class);
    複製代碼
  2. SEL的反射

    經過方法的字符串形式實例化方法。

    SEL selector = NSSelectorFromString(@"setName"); 
    [stu performSelector:selector withObject:@"Mike"];
    複製代碼

    將方法變成字符串。

    NSStringFromSelector(@selector*(setName:));
    複製代碼

二十七.如何對iOS設備進行性能測試?

  1. app使用過程當中,接聽電話。能夠測試不一樣的通話時間的長短,對於通話結束後,原先打開的app的響應,好比是否停留在原先界面,繼續操做時的相應速度等。
  2. app使用過程當中,有推送消息時,對app的使用影響
  3. 設備在充電時,app的響應以及操做流暢度
  4. 設備在不一樣電量時(低於10%,50%,95%),app的響應以及操做流暢度
  5. 意外斷電時,app數據丟失狀況
  6. 網絡環境變化時,app的應對狀況如何:是否有適當提示?從有網絡環境到無網絡環境時,app的反饋如何?從無網絡環境回到有網絡環境時,是否能自動加載數據,多久才能開始加載數據
  7. 多點觸摸的狀況
  8. 跟其餘app之間互相切換時的響應
  9. 進程關閉再從新打開的反饋
  10. IOS系統語言環境變化時

今天的分享就到這裏了,未完待續

小編這呢,給你們推薦一個優秀的iOS交流平臺,平臺裏的夥伴們都是很是優秀的iOS開發人員,咱們專一於技術的分享與技巧的交流,你們能夠在平臺上討論技術,交流學習。歡迎你們的加入(想要加入的可加小編微信15673450590)。

相關文章
相關標籤/搜索