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。