1. 程式人生 > >iOS面試題系列之Objective-C相關

iOS面試題系列之Objective-C相關

1、簡述你專案中常用的設計模式。它們有什麼優缺點?

常用的設計模式有:代理、觀察者、單例。

(1)單例:它是用來限制一個類只能建立一個物件。這個物件中的屬性可以儲存全域性共享的資料。所有的類都能訪問、設定此單例中的屬性資料。

優點:是它只會建立一個物件容易供外界訪問,節約效能。

缺點:是一個類只有一個物件,可能造成責任過重,在一定程度上違背了“單一職責原則”。單例模式中沒有抽象層,所以單例類的擴充套件有很大的困難。不能過多建立單例,因為單例從建立到程式關閉前會一直存在,過多的單例會影響效能,浪費系統資源。

(2)觀察者(KVO):它提供了觀察某一屬性變化的方法。當指定物件的屬性發生改變後,它會自動通知相應的觀察者。

優點:能提供被觀察者屬性的新值與舊值。用keypaths來觀察屬性,因此也可以觀察巢狀物件。

缺點:需要註冊觀察者,實現observeValueForKeyPath:方法,屬性必須通過KVC的方法來修改。否則觀察者收不到通知。

(3)代理:可以實現類與類之間一對一的通訊。

優點:代理協議方法都有清晰的定義。代理方法可以設定可選或必須實現。

缺點:需要定義協議方法,需要設定代理物件,代理物件實現協議方法。記憶體管理方面,需要注意迴圈引用問題。

2、代理模式能否實現一對多的通訊?

可以,採用多播委託的方式來實現。多播委託:它是指允許建立方法的呼叫列表或者連結串列的能力。當多播委託被呼叫時,列表中的方法均自動執行。

普通代理只能是一對一的回撥,無法做到一對多的回撥,而多播委託正式對delegate的一種擴充套件與延伸,多了一個註冊和取消的過程。任何需要回調的物件都必須先註冊。

3、 重複註冊通知會有問題嗎?

不會出現問題,若多次傳送同一通知,對方就會多次響應。如果重複註冊通知,也會有多次響應的效果。為了避免重複註冊通知而造成的錯誤,建議每次註冊一個通知前,可以移除一次該通知。

4、專案中是否用過多執行緒程式設計?簡述你常用的多執行緒實現方式?

常用的是GCD。

GCD是蘋果開發中一個多核程式設計的解決方案。GCD的佇列分為兩種型別,SerialDispatchQueue與ConcurrentDispatchQueue。系統預設提供了一個dispatch_get_main_queue,一個dispatch_get_global_queue。

5、簡述NSOperationQueue與GCD的區別。

(1) GCD是底層的C語言構成的API。NSOperationQueue及相關物件是Objc物件。在GCD中,在佇列中執行的是由block構成的任務,這是一個輕量級的資料結構。而Operation作為一個物件,為我們提供了更多的選擇。

(2) 在NSOperationQueue中,我們可以取消任務,而GCD沒法停止已經加入queue的block。

(3) NSOperation能夠方便的設定依賴關係。還能設定NSOperation的priority優先順序,能夠使同一個並行佇列中的任務區分先後地執行。在GCD中,我們只能區分不同任務佇列的優先順序,如果要區分block任務優先順序也需要大量複雜程式碼。
NSOperation還可以設定併發數。

6、實現多執行緒有哪幾種方式?

(1)NSThread:detachNewThreadSelector:

(2)繼承NSOperation

(3)GCD:dispatch_async

(4)NSObject:performSelectorInBackground:

7、KVC、KVO是什麼?簡述KVO的實現原理。KVO能否監聽陣列?如何實現?

KVC:鍵值編碼,它是一種間接訪問物件例項變數機制,可以不通過存取方法訪問物件的例項變數。

KVO:鍵值觀察,它可以使物件獲取其他物件屬性變化的通知機制。

鍵值編碼和鍵值觀察是根據isa-swizzling技術來實現的,主要依據runtime的強大動態能力。當給某個物件第一次新增KVO監聽的時候,執行時會動態的建立一個被監聽物件的派生類,然後重寫KVO需要監聽屬性值對應的setter方法,在這個setter方法中實現了通知機制。最後將被監聽物件的isa指向動態建立的派生類。這樣當使用KVC修改屬性值時,就會呼叫動態建立的派生類中對應的setter方法,觸發通知機制,從而實現了KVO了。
KVO可以監聽陣列。

實現 NSMutableArray 的增刪改操作遵從 KVC 的規則,需要實現其對應方法:

增操作 -insertObject:inAtIndex: 或者 -insert:atIndexes:

刪操作 -removeObjectFromAtIndex: 或者 -removeAtIndexes:

改操作 -replaceObjectInAtIndex:withObject: 或者 -replaceAtIndexes:with:

並將這些介面暴露給呼叫者,在對陣列進行操作時需使用上述實現的介面。

8、簡單說下C++,JAVA,Objective-C這幾種語言有什麼區別?

Objective-C與JAVA都是單繼承語言,C++是多繼承語言。

Objective-C不支援名稱空間機制,通過類名前面加字首NS來區分。

Objective-C與JAVA不支援運算子過載。

Objective-C協議可選實現,JAVA的介面必須實現。

9、陣列新增nil元素有問題嗎?字典object與key可以設定為nil嗎?

會有問題,陣列中新增nil元素,程式會崩潰!報object cannot be nil錯誤。字典的key不能為nil,否則會造成崩潰。字典的object也不能為nil。

10、oc中向一個nil物件傳送訊息會出現問題嗎?

不會出現問題,因為objc是動態語言,每個方法在執行時會被動態轉為訊息傳送。即:objc_msgSend(receiver,selector)。objc在向一個物件傳送訊息時,runtime庫會根據物件的isa指標找到該物件實際所屬的類,然後在該類中的方法列表以及其父類方法列表中尋找方法執行,然後在傳送訊息的時候,objc_msgSend方法不會返回值,所謂的返回內容都是具體呼叫時執行的。 那麼,回到本題,如果向一個nil物件傳送訊息,首先在尋找物件的isa指標時就是0地址返回了,所以不會出現任何錯誤。

11、可變陣列是執行緒安全的嗎?什麼情況下不安全?可以加鎖嗎?它鎖住的是新增元素操作還是陣列物件?

可變陣列不是執行緒安全的,在非同步讀取資料的情況下是不安全的。可以加鎖,鎖住的是陣列。

12、陣列能新增一個block嗎?陣列新增一個block之後再取出來,這個block還有用嗎?

可以,還有用,它只是多retain了一次

13、NSMutableDictionary中的setObject:forKey:與setValue:forKey:方法有什麼區別?

setObject:forkey:中value是不能夠為nil的,不然會報錯。

setValue:forKey:中的value能夠為nil,但是當value為nil的時候,會自動呼叫removeObject:forKey方法。

setValue:forKey:中的key的引數只能是NSString型別,而setObject:forKey是可以任何型別。

14、簡述copy與mutablecopy的區別。

(1)非容器物件:

對不可變物件:copy是指標複製(淺拷貝), mutableCopy是物件複製(深拷貝)。
對可變物件:copy和mutableCopy都是物件複製。

(2)容器物件:

對不可變物件:copy是指標複製,mutableCopy是物件複製。

對可變物件:copy和mutableCopy都是物件複製,只是返回的物件型別不一樣,前者返回的是不可變物件,後者返回的是可變物件。

容器物件複製僅限於物件本身,物件元素仍然是指標複製。

15、簡述weak與assign的區別。

weak用來修飾物件,不能修飾基本資料型別。assign一般用來修飾基本資料型別。weak修飾物件,在物件釋放之後會把物件置為nil。

16、ARC下,不顯示指定任何屬性關鍵字時,預設的關鍵字有哪些?

基本資料型別預設修飾關鍵字:atomic,readwrite,assign

普通的OC物件預設修飾關鍵字:atomic,readwrite,strong

17、weak在什麼時候置空?

runtime 對註冊的類, 會進行佈局,對於 weak 物件會放入一個 hash 表中。 用 weak 指向的物件記憶體地址作為 key,當此物件的引用計數為0的時候會 dealloc,假如 weak 指向的物件記憶體地址是a,那麼就會以a為鍵, 在這個 weak 表中搜索,找到所有以a為鍵的 weak 物件,從而設定為 nil。

我們可以設計一個函式(虛擬碼)來表示上述機制:

objc_storeWeak(&a, b)函式:

objc_storeWeak函式把第二個引數–賦值物件(b)的記憶體地址作為鍵值key,將第一個引數–weak修飾的屬性變數(a)的記憶體地址(&a)作為value,註冊到 weak 表中。如果第二個引數(b)為0(nil),那麼把變數(a)的記憶體地址(&a)從weak表中刪除,
你可以把objc_storeWeak(&a, b)理解為:objc_storeWeak(value, key),並且當key變nil,將value置nil。

在b非nil時,a和b指向同一個記憶體地址,在b變nil時,a變nil。此時向a傳送訊息不會崩潰:在Objective-C中向nil傳送訊息是安全的。

而如果a是由assign修飾的,則: 在b非nil時,a和b指向同一個記憶體地址,在b變nil時,a還是指向該記憶體地址,變野指標。此時向a傳送訊息極易崩潰。

下面我們將基於objc_storeWeak(&a, b)函式,使用虛擬碼模擬“runtime如何實現weak屬性”:

// 使用虛擬碼模擬:runtime如何實現weak屬性
id obj1;
objc_initWeak(&obj1, obj);
/obj引用計數變為0,變數作用域結束/
objc_destroyWeak(&obj1);

下面對用到的兩個方法objc_initWeak和objc_destroyWeak做下解釋:

總體說來,作用是: 通過objc_initWeak函式初始化“附有weak修飾符的變數(obj1)”,在變數作用域結束時通過objc_destoryWeak函式釋放該變數(obj1)。

下面分別介紹下方法的內部實現:

objc_initWeak函式的實現是這樣的:在將“附有weak修飾符的變數(obj1)”初始化為0(nil)後,會將“賦值物件”(obj)作為引數,呼叫objc_storeWeak函式。
obj1 = 0;
obj_storeWeak(&obj1, obj);

也就是說:
weak 修飾的指標預設值是 nil (在Objective-C中向nil傳送訊息是安全的)
然後obj_destroyWeak函式將0(nil)作為引數,呼叫objc_storeWeak函式。
objc_storeWeak(&obj1, 0);
前面的原始碼與下列原始碼相同。

// 使用虛擬碼模擬:runtime如何實現weak屬性
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
/* … obj的引用計數變為0,被置nil … */
objc_storeWeak(&obj1, 0);

objc_storeWeak函式把第二個引數–賦值物件(obj)的記憶體地址作為鍵值,將第一個引數–weak修飾的屬性變數(obj1)的記憶體地址註冊到 weak 表中。如果第二個引數(obj)為0(nil),那麼把變數(obj1)的地址從weak表中刪除,在後面的相關一題會詳解。

以上內容總結如下:

(1)從weak表中獲取廢棄物件的地址為鍵值的記錄

(2)將包含在記錄中的所有附有__weak修飾符變數的地址,賦值為nil

(3)從weak表中刪除該記錄

(4)從引用計數表中刪除廢棄物件的地址為鍵值的記錄。

18、自動釋放池用過嗎?它是什麼時候釋放?什麼情況下物件會被加入到自動釋放池,它會加入到哪個自動釋放池?

主執行緒預設開啟runloop,同時runloop會自動建立一個autoreleasepool,autorelease物件會自動被加入autoreleasepool中,一次runloop後清空自動釋放池。用__autoreleasing修飾符修飾,或類方法建立會自動加入autoreleasepool。它會加入到最近的autoreleasepool中。

19、你知道iOS中有哪些資料持久化方式嗎?請簡要加以說明。

iOS中資料持久化方式有:SQLite3資料庫,CoreData,檔案歸檔,屬性列表(plist檔案寫入)。

屬性列表:涉及的主要類是NSUserDefaults,儲存小量的資料。

檔案歸檔:物件必須實現NSCoding協議。實現initWithCoder:方法與encodeWithCoder方法。同時也建議實現NSCopying協議。

SQLite3資料庫:SQLite是一個開源的嵌入式關係資料庫。可移植性好,容易使用,需要記憶體開銷小。適合嵌入式裝置。

CoreData:它可以使用SQLite儲存資料,而且不需要寫SQL語句。另外它還可以使用XML方式儲存資料。要使用CoreData,需要在Xcode中的資料模型編輯器中設計好各個實體以及定義好他們的屬性和關係。通過操作這些物件來完成資料的持久化。

20、fmdb中支援多執行緒嗎?它是如何實現的!

支援多執行緒。它裡面有個FMDatabaseQueue類。它看似是一個佇列,實際上它本身並不是,它繼承NSObject,通過內部建立一個Serial的dipatch_queue_t來處理inDatabase和inTransaction傳入的Block,所以當我們在主執行緒(或者後臺)呼叫inDatabase或者inTransaction時,程式碼實際上是同步的。FMDatabaseQueue如此設計的目的是為了避免併發訪問資料庫的執行緒安全問題,所有的資料庫訪問都是同步執行,比@synchronized與NSLock效率高。

21、簡述category與extension的區別。Category與extension載入的時機。

category中只能增加方法,不可新增例項變數(可新增屬性)。extension不僅可以增加方法,還可以增加例項變數或屬性(私有的)。extension不能像category一樣有獨立的實現部分。category是執行時決定的。extension是編譯期決定的。

22、category的方法能被子類繼承嗎?它覆蓋原有類的方法後,原有類的方法還能呼叫嗎?如果能,你說明理由。

category的方法可以被子類繼承。category並不是絕對的覆蓋了類的同名方法,而是category的方法排在了類的同名方法之前,方法的檢索方式是順序檢索,所以在呼叫方法時,呼叫到的同名方法是category,從而產生了覆蓋。
利用執行時遍歷方法列表,可以呼叫被category覆蓋的方法。

23、 擴充套件一個類的方式用繼承好還是category好?請說明理由。

用類目好。因為繼承還需要定義子類。類目不需要通過建立子類來增加現有類的方法。用category去重寫一個類的方法,僅僅只對本category有效,不會影響到其他類與原有類的關係。

24、 block有幾種型別?block的實現?

block分為三種類型:

_NSConcreteGlobalBlock

_NSConcreteStackBlock

_NSConcreteMallocBlock

block:匿名函式

25、 Swift用的多嗎?簡單的說說1.0與2.0的區別。

swift2.0新增:guard語句,異常處理,協議擴充套件,列印語句改變,avaliable檢查,do-while語句重新命名:repeat-while,defer關鍵字

26、 在Swift用有沒有用過defer關鍵字?

對defer語句進行的延遲,函式結束時呼叫。

27、 SDWebImage的圖片儲存在什麼位置?

圖片儲存在沙盒中的library/caches資料夾下。

28、 Objective-C中類目為什麼不能新增例項變數?

因為在執行時,物件的記憶體佈局已經確定,如果新增例項變數會破壞類的內部佈局。

29、 Objective-C中的協議預設是@optional還是@require?在使用協議的時候應當注意哪些問題?

Objective-C中的協議默是必須實現的@require,使用協議的時候應當注意迴圈引用問題,多個協議之間採用逗號分隔。

30、 Objective-C的協議與JAVA中的介面有什麼區別?

OC中的協議可選實現,JAVA中的介面必須實現。

31、 類目的應用場景有哪些?

(1)可以把類的實現分開在幾個不同的檔案裡面

(2)宣告私有方法

(3)模擬多繼承

(4)把Framework的私有方法公開

32、 self與super的區別?

super本質上是一個編譯器標示符,它和self指向的是同一個訊息接受者,兩者不同在於:super會告訴編譯器,呼叫class這個方法時,要去父類方法,而不是本類方法。

33、 圖片快取為什麼不儲存到沙盒下的tmp檔案目錄中?

因為tmp資料夾是用來存放臨時檔案,iTunes不會備份和恢復此目錄,此目錄下檔案可能會在應用退出後刪除。

34、 NSURLConnection與NSURLSession。

NSURLConnection它是CoreFoundation/CFNetwork框架的API之上的一個抽象。

NSURLConnection這個名字實際指代Foundation框架的URL載入系統中一系列有關聯的元件:NSURLRequest、NSURLResponse、NSURLProtocol、NSURLCache、NSHTTPCookieStorage、NSURLCredentialStorage以及同名類NSURLConnection。NSURLRequest 被傳遞給 NSURLConnection。被委託物件(遵守以前的非正式協議 和 )非同步地返回一個 NSURLResponse 以及包含伺服器返回資訊的 NSData。

NSURLSession包括:NSURLRequest、NSURLCache、NSURLSession、NSURLSessionConfiguration、NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask。
它與NSURLConnection的區別在於:NSURLSession最直接的改進就是可以配置每個Session的快取,協議,cookie以及正式策略。甚至跨程式共享這些資訊。每個NSURLSession物件都由一個NSURLSessionConfiguration物件來進行初始化。
session task:負責處理資料的載入以及檔案和資料在客戶端與伺服器之間的上次和下載。

35、 簡述ARC與MRC的區別。

ARC:自動引用計數。MRC:手動引用計數。ARC是把記憶體交給系統管理。系統會在編譯的時候自動插入retain/release。MRC則需要手動管理物件的引用計數。當你alloc,new,copy,mutablecopy或者retain一個物件時,你就有義務向它傳送一條release或autorelease訊息。

36、 簡述ARC的實現原理。它在什麼時機插入retain/release?

ARC:自動引用計數。它會在物件建立或者消亡的時候自動插入retain/release。達到自動管理記憶體的目的。

37、 Framework與Library的區別?動態庫與靜態庫的區別?

library與Framework的區別:

在iOS中,Library 僅能包含編譯後的程式碼,即 .a 檔案。
但一般來說,一個完整的模組不僅有程式碼,還可能包含.h 頭文修的、.nib 檢視檔案、圖片資原始檔、說明文件。(像 UMeng 提供的那些庫,整合時,要把一堆的檔案拖到Xcode中,配置起來真不是省心的事。
Framework 作為 Cocoa/Cocoa Touch 中使用的一種資源打包方式,可以上述檔案等集中打包在一起,方便開發者使用(就像Bundle)。

靜態庫與動態庫的區別:

簡單的說,靜態連結庫是指模組被編譯合併到應用中,應用程式本身比較大,但不再需要依賴第三方庫。執行多個含有該庫的應用時,就會有多個該庫的Copy在記憶體中,冗餘。
動態庫可以分開發布,在執行時查詢並載入到記憶體,如果有通用的庫,可以共用,節省空間和記憶體。同時庫也可以直接單獨升級,或作為外掛釋出。

38、 什麼是runloop?

一般來說,一個執行緒一次只能執行一個任務,執行完成後執行緒就會退出,如果我們需要一個機制,讓執行緒能隨時處理事件但並不退出。程式碼邏輯如下:


function loop() {
        initialize();
        do {
    var message = get_next_message();
    process_message(message);
} while(message != quit)
}

這種模型我們通常稱之為EventLoop(事件迴圈)。RunLoop實際上是一個物件,這個物件管理了其需要處理的事件和訊息。並提供了一個入口函式來執行上面EventLoop邏輯。在OSX/iOS系統中,提供了兩個這樣的物件:NSRunLoop和CFRunLoopRef。

CFRunLoopRef是在CoreFoundation框架內,它提供了純C函式的API,所有這些API都是執行緒安全的。

NSRunLoop是基於CFRunLoopRef的封裝,提供了面向物件的API,這些API不是執行緒安全的。

蘋果不允許直接建立RunLoop,只提供了兩個自動獲取的函式:CFRunLoopGetMain()和CFRunLoopGetCurrent()。

執行緒和RunLoop之間是一一對應的。

39、#include與#import的區別?#import與@class的區別?

“#include”與”#import”功能一樣,都是匯出標頭檔案。只是#import不會引起交叉編譯,可以確保標頭檔案只匯入一次。#import會包含這個類的所有資訊。包括例項變數和方法,而@class只是告訴編譯器,它後面宣告的名稱是類的名稱,至於類的定義,後面會告訴你。使用#import編譯效率高,可以防止相互包含的編譯錯誤。

40、Static與const的區別?

const表示只讀的意思,只在宣告中使用。

static一般有2個作用,規定作用域和儲存方法。對於區域性變數,static規定其為靜態儲存區,每次呼叫的初始值為上一次呼叫的值,呼叫結束後儲存空間不釋放。

對於全域性變數,如果以檔案劃分作用域的話,此變數只在當前檔案可見,對於static函式也是在當前模組內函式可見。

41、簡述GET請求與POST請求的區別。

(1)POST 需要明確制定方法 GET不需要 ,並且預設就是GET方法,並且GET有快取,POST沒有快取

(2)GET的引數放在URL的後面,並且第一個引數用?拼接,後面的從第二個引數開始,直到最後一個,如果有多個,用&分割;POST 的引數放在請求體裡面,並且第一個引數,不用,後面從第二開始,直到最後,如果有多個,用&分割;

(3)GET 一般用於獲取資料,POST向伺服器提交資料用到

(4)GET的引數是暴漏在位址列的,不安全;POST的引數隱藏在請求體裡面,相對安全一點;

(5)GET請求沒有請求體,POST請求有請求體。

(6)GET請求提交資料受瀏覽器限制,1k,POST請求理論上無限制。

42、屬性用__block修飾時在記憶體中會發生什麼變化?

為什麼在block外面用weak修飾屬性來打破迴圈,在block還需要把屬性轉換成strong。

43、談談block與函式的區別。

block可以寫在方法裡面,函式需要寫在方法外面。block可以訪問方法中的區域性變數。

44、你瞭解runloop嗎?它有幾種模式?簡要的說下它的應用場景。

runloop模式:

Default:

NSDefaultRunLoopMode(Cocoa)、kCFRunLoopDefaultMode(CoreFoundation)

Connection:

NSConnectionReplyMode

Modal:

NSModalPanelRunLoopMode

Event tracking:

NSEventTrackingRunLoopMode

Common modes:

NSRunLoopCommonModes(Cocoa)、kCFRunLoopCommonModes(CoreFoundation)

應用場景:

(1)使用埠或自定義輸入源與其他執行緒通訊。

(2)線上程中使用計時器

(3)使用任意的performSelector方法

(4)保持執行緒去執行一個週期任務。

45、你工作中用到的版本管理工具是什麼?

用的是git工具來進行版本管理。

46、你用過git工具嗎?用過哪些常見的命令?

git init,git add, git commit,git merge,git branch,git checkout,git pull,git push等

47、CoreAnimation常用的動畫有哪些型別?

所有的核心動畫的動畫類都從CAAnimation類繼承而來。CAAnimationGroup組動畫,CATransition轉場動畫,CABasicAnimation:基礎動畫,CAKeyframeAnimation關鍵幀動畫。

48、GCD中系統提供了幾種queue?

兩種:DispatchSerialQueue、DispatchConcurrentQueue。

49、二叉搜尋樹的概念及時間複雜度是多少?

O(n)

50、block中的weak self,是任何時候都需要加的麼?

不一定,可加可不加。將block置nil也可以打破迴圈引用。

51、GCD的queue,main queue中執行的程式碼,一定是在main thread麼?

是的。一定是在main thread。

52、你在使用資料庫的過程中有沒有遇到過問題?如何解決?

遇到過多執行緒操作資料庫讀寫死鎖問題,採用fmdb中提供的回滾的方式解決

53、簡述iOS中的沙盒機制。

iOS中的沙盒機制是一種安全體系,它規定了應用程式只能在為該應用建立的資料夾讀取檔案,不可以訪問其他地方的內容。所有非程式碼檔案都儲存在這個地方。如圖片,聲音,屬性列表及文字檔案等。

(1)每個應用程式都在自己的沙盒內

(2)不能隨意跨越自己的沙盒去訪問別的應用程式沙盒的內容

(3)應用程式向外請求或者接收資料都需要經過許可權認證。

沙盒目錄結構這種,因為應用是在沙箱(sandbox)中的,在檔案讀寫許可權上受到限制,只能在幾個目錄下讀寫檔案:

Documents:應用中使用者資料可以放在這裡,iTunes備份和恢復的時候會包括此目錄

tmp:存放臨時檔案,iTunes不會備份和恢復此目錄,此目錄下檔案可能會在應用退出後刪除

Library:儲存程式的預設設定或其他狀態資訊。

Library/Caches:存放快取檔案,iTunes不會備份此目錄,此目錄下檔案不會在應用退出刪除

54、字串為什麼要用copy修飾?

是為了防止mutablestring被無意中修改,NSMutableString是NSString的子類。因此NSString指標可以持有NSMutableString物件。

55、nonatomic與atomic有什麼區別?

atomic是Objective-C使用的一種執行緒保護技術,它是為了防止寫操作在未完成的時候被另外一個執行緒讀取。從而造成資料錯誤。這種機制是非常耗費系統資源的,所以在iphone這種小的移動裝置上,如果沒有使用多執行緒間的通訊程式設計。建議使用nonatomic。

預設的訪問器是原子操作,就是說在多執行緒環境下,解析的訪問器提供一個對屬性安全訪問,從獲取器得到的返回值或者通過設定器設定的值可以一次完成,即便是多執行緒也在對其進行訪問,如果不指定nonatomic ,在自己管理記憶體的環境中,解析的訪問器保留並自動釋放保留的值,如果是指定了nonatomic,訪問器只是簡單的返回一個值。

56、@synthesize與@dynamic的區別?

@synthesize:如果你沒有手動實現setter方法和getter方法,編譯器會自動為幫你生成setter方法和getter方法。

@dynamic:告訴編譯器屬性的setter和getter方法由使用者自己實現,不自動生成。如果一個屬性宣告為@dynamic var,又沒有提供setter和getter方法,編譯的時候不會有問題,如果程式中執行到person.name = newName;或newName=person.name時候就會導致程式崩潰。因為”unrecognized selector sent to instance …”這就是動態繫結。

57、@property(copy)NSMutableArray *array;這句程式碼有什麼問題?如果有請簡述原因;

(1)新增、刪除、修改陣列內的元素的時候,程式會因為找不到對應的方法而崩潰,因為copy就是複製一個不可變的NSArray物件。

(2)沒有使用nonatomic屬性修飾符,預設是 atomic修飾,這樣會嚴重影響效能。

58、NSString *str = @“hello world!”與NSString *str = [[NSString alloc] initWithString:@”hello world!”];在記憶體管理上有什麼區別?

在MRC中,前者表示,你不持有這個物件,所以不需要手動管理其記憶體。後者意味著你持有這個字串,需要自己手動管理記憶體,對其進行釋放。

59、對於語句NSString*obj = [[NSData alloc] init]; obj在編譯時和執行時分別是什麼型別的物件?

編譯時是NSString型別物件,執行時時NSData型別物件
首先,宣告NSString*testObject是告訴編譯器,obj是一個指向某個Objective-C物件的指標,因為不管指向的是什麼型別的物件,一個指標所佔的記憶體空間都是固定的,所以這裡宣告稱任何型別的物件,最終生成的可執行程式碼都是沒有區別的。這裡限定了NSString只不過是告訴編譯器,請把obj當做一個NSString來檢查,如果後面呼叫了非NSString的方法,會產生警告,接著,你建立了一個NSData物件,然後把這個物件所在的記憶體地址儲存在obj裡。那麼執行時,obj指向的記憶體空間就是一個NSData物件。你可以把obj當做一個NSData物件來用。

60、self.name=object與name=object在記憶體管理上有什麼區別?

前者通過呼叫setter方法設定值,後者是普通的賦值操作。

61、為什麼property宣告中只有”copy”特性而沒有“mutableCopy”特性?

這是由於當宣告property為”copy”特性時,系統會自動根據receiver的特點決定使用copy(已含retain的情況)還是mutableCopy。

62、Objective-C中id與void*有什麼區別?id與instancetype有什麼區別?nil、null、NULL三者有什麼區別?

Objective-C中id與void*區別:

id是指向OC類物件的指標,它可以宣告為任何類物件的指標,當在OC中使用id時,編譯器會假定你知道,id指向哪個類的物件。與void*不同,void*編譯器不知道也不假定指向任何型別的指標。

id與instancetype區別:

id返回的是id型別,instancetype返回的是所在類的型別。

相同點是同樣都是作為方法的返回型別。

區別:

(1) instancetype可以返回和方法所在類相同型別的物件,id只能返回未知型別的物件。

(2) instancetype只能作為返回值,id可以作為引數。

nil、Nil、NULL三者區別:

nil是一個指向不存在的物件指標(物件空指標)。Nil是指向不存在的類指標(類空指標)。NULL指向其他型別的空指標。NSNull在集合物件中,表示空值的物件。

63、資料解析方式有幾種?他們有什麼區別?你專案中採用的是哪種資料解析方式?

JSON和XML。

64、用預處理指令#define宣告一個常數,用以表明1年中有多少秒(忽略閏年問題)

“#define SECONDS_PER_YEAR(60*60*24*365)UL”

65、寫一個”標準”巨集MIN ,這個巨集輸入兩個引數並返回較小的一個。

“#define MIN(X,Y) ((X)>(Y)?(X):(Y))”

66、+load和+initialize 的區別是什麼?

+initialize:第一次初始化這個類之前被呼叫,我們用它來初始化靜態變數。

+load方法會在載入類的時候就被呼叫,也就是iOS應用啟動的時候,就會載入所有的類。

+initialize方法類似一個懶載入,如果沒有使用這個類,系統預設不會去呼叫這個方法,且預設只加載一次。

如果是在類別中,+load方法會全都執行,但是類別中的load方法會後於類中的方法,+initialize方法會覆蓋類中的方法,只執行一個。

+initialize的呼叫發生在+init方法之前。子類會去呼叫父類的+initialize方法。

67、new和alloc/init的區別

概括來說,new和alloc/init在功能上幾乎是一致的,分配記憶體並完成初始化。
差別在於,採用new的方式只能採用預設的init方法完成初始化。
而採用alloc的方式可以用其他定製的初始化方法。

68、如果讓你設計介面與API,應該注意點什麼?

(1)用字首避免名稱空間衝突

(2)提供“全能初始化方法”

(3)實現description方法

(4)儘量使用不可變物件

(5)使用清晰而協調的命名方法

(6)為私有方法名加字首

(7)錯誤處理

(8)實現NSCopying協議。

69、你在專案中用過懶載入嗎?能簡單的說說懶載入嗎?

懶載入又稱為延遲載入。寫的是其get方法。如果是懶載入的話則一定要注意先判斷是否已經有了,如果沒有那麼再去進行例項化。

好處是不必將建立物件的程式碼全部寫在viewDidLoad方法中,程式碼的可讀性更強。每個控制元件的getter方法中分別負責各自的例項化處理,程式碼彼此之間的獨立性強,鬆耦合。

70、程序和執行緒的區別與聯絡。

程序是個靜態的容器,裡面容納了很多個執行緒,執行緒是一系列方法的線性執行路徑。

71、簡述記憶體分割槽情況。

棧區:存放函式的引數值,區域性變數的值等。由編譯器自動分配釋放

堆區:由程式設計師分配釋放。程式設計師如果不釋放,則程式結束時可能由系統回收

全域性區:全域性變數和靜態變數是儲存在一塊的。初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在另一塊區域。程式結束後由系統釋放。全域性區可分為未初始化全域性區:.bbs段和初始化全域性區:data段。

常量區:存放常量字串,程式結束後由系統釋放

程式碼區:存放函式體的二進位制程式碼。

72、佇列與棧有什麼區別?

棧:限定僅在表尾進行插入或刪除操作的線性表。表尾是棧頂,表頭是棧底。它又稱後進先出線性表。

佇列:是一種先進先出的線性表。它只允許在表的一端進行插入,而在另一端刪除元素。

73、Objective-C中多執行緒的程式設計方式有幾種

pthread、NSThread、NSOperation、GCD。

74、Objective-C執行時(runtime)機制瞭解嗎?簡單的說說物件呼叫方法的過程。

(1)在物件類的dispatch table中嘗試找到該訊息。如果找到了,跳到相應的函式IMP去執行實現程式碼

(2)如果沒有找到,Runtime會發送+resolveInstanceMethod: 或者 +resolveClassMethod: 嘗試去resolve這個訊息

(3)如果resolve方法返回NO,Runtime就傳送 -forwardingTargetForSelector: 允許你把這個訊息轉發給另一個物件;

(4)如果沒有新的目標物件返回,Runtime 就會發送 -methodSignatureForSelector: 和 -forwardInvocation: 訊息。你可以傳送 -invokeWithTarget: 訊息來手動轉發訊息或者傳送 -doesNotRecognizeSelector: 丟擲異常。

參考資料如下:

本文內容中部分來自網路,後續會持續更新完善。歡迎一起學習交流!

如需轉載,請註明出處