1. 程式人生 > >【IOS學習】面試iOS工程師的相關問題

【IOS學習】面試iOS工程師的相關問題

1. OC中,與alloc語義相反的方法是dealloc還是release?與retain語義相反的方法是dealloc還是release?為什麼?需要與alloc配對使用的方法是dealloc還是release,為什麼?
以下是針對MRC(手動記憶體釋放)模式:
與alloc語義相反的方法是dealloc,與retain語義相反的方法是release。
alloc是為物件在記憶體中開闢空間,而dealloc則是物件銷燬時釋放空間。
retain方法是物件開闢空間以後使物件的引用計數器加1,而release是物件的引用計數器減1。
需要與alloc配對的方法是release,因為物件建立以後,物件的引用計數器自動加1,
而呼叫release方法後,物件的引用計數器歸0,系統會自動呼叫dealloc方法釋放空間。
2. 在一個物件的方法裡面:self.name = @"object";和 _name = @"object"有什麼不同嗎?
self.name = @"object"; 是通過點語法修改屬性name的值。
本質上使用的是name屬性的setter方法進行的賦值操作,實際上執行的程式碼是
[self setName:@"object"];
例如:
@property(nonatomic, strong) NSString *name;
//根據@property關鍵詞,系統自動生成setter方法。


(void)setName:(NSString )name{
//根據strong關鍵詞
[name retain]; //記憶體計數+1
[_name release]; //把之前指標指向的內容記憶體計數-1
_name = name; //指向新內容
}
_name = @“object”; 只是單純的把‘_name’指標指向‘@"object"’字串物件所在的地址,
沒有呼叫方法。
3. 這段程式碼有什麼問題嗎?
-(void)setAge:(int)newAge{
self.age = newAge;
}
在age屬性的setter方法中,不能通過點語法給該屬性賦值。
會造成setter方法的迴圈呼叫。因為self.age = newAge;
本質上是在呼叫 [self setAge:newAge]; 方法。
解決迴圈呼叫的方法是方法體修改為 _age = newAge;
另外 變數名稱不能使用new開頭!
4. 以下每行程式碼執行後,person物件的retain count分別是多少?
Person person = [[Person alloc] init];
[person retain];
[person release];
[person release];
Person person = [[Person alloc] init]; =1
[person retain]; +1 = 2
[person release]; -1 = 1
[person release]; -1 = 0
記憶體計數技術規律
alloc,new,copy 記憶體計數 = 1
retain +1
release -1
UIView addSubview +1
NSMutableArray addObject +1
5. 這段程式碼有什麼問題,如何修改?
for(int i = 0; i < someLargeNumber; i++){
NSString string = @“Abc”;
string = [string lowercaseString];
string = [string stringByAppendingString:@“xyz”];
NSLog(@“%@“, string);
}
程式碼本身不會報錯。
但是猜測出題者的意思是要迴圈新增為 abcxyzxyzxyz.....這樣的形式。
如果是想在Abc後面拼接多個xyz字串的話,
則需要把"NSString string = @“Abc”;" 這行程式碼放在迴圈語句外面。
*6. 簡要敘述面向物件的特點,特別是多型。
封裝
封裝是物件和類概念的主要特性。它是隱藏內部實現,提供外部介面,可以看作是“包裝”。
封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,
對不可信的進行資訊隱藏。
封裝的目的是增強安全性和簡化程式設計,使用者不必瞭解具體的實現細節,而只是要通過外部介面,
以特定的訪問許可權來使用類的成員。
好處:可以隱藏內部實現細節。通過大量功能類封裝,加快後期開發速度。
繼承
面向物件程式設計 (OOP) 語言的一個主要功能就是“繼承”。
繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下
對這些功能進行擴充套件。
通過繼承建立的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”。
繼承的過程,就是從一般到特殊的過程。在考慮使用繼承時,有一點需要注意,
那就是兩個類之間的關係應該是“屬於”關係。
例如,Employee(僱員)是一個人,Manager(領導)也是一個人,因此這兩個類都可以繼承Person類。
但是 Leg(腿) 類卻不能繼承 Person 類,因為腿並不是一個人。
多型
多型性(polymorphism)是允許你將父物件設定成為和一個或更多的他的子物件相等的技術,
賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。
簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。
不同物件以自己的方式響應相同的訊息的能力叫做多型。
意思就是假設生物類(life)都用有一個相同的 方法-eat;那人類屬於生物,豬也屬於生物,
都繼承了life後,實現各自的eat,但是呼叫是我們只需呼叫各自的eat方法。
也就是不同的物件以 自己的方式響應了相同的訊息(響應了eat這個選擇器)。
實現多型,有二種方式,覆蓋,過載。
• 覆蓋(override),是指子類重新定義父類的虛擬函式的做法。
• 過載(overload),是指允許存在多個同名函式,而這些函式的引數表不同
(或許引數個數不同,或許引數型別不同,或許兩者都不同)。
這裡注意:OC沒有過載,因為OC只認函式名,不認引數型別。OC不允許存在多個同名函式。
總結:封裝可以隱藏實現細節,使得程式碼模組化;繼承可以擴充套件已存在的程式碼模組(類);
它們的目的都是為了——程式碼重用。
而多型則是為了實現另一個目的——介面重用!
多型的作用,就是為了類在繼承和派生的時候,保證使用“家譜”中任一類的例項的某一屬性時的正確呼叫。
在類層次中,子類只繼承一個父類的資料結構和方法,則稱為單重繼承。
在類層次中,子類繼承了多個父類的資料結構和方法,則稱為多重繼承。
*7. objective-c 所有物件間的互動是如何實現的?
在物件間互動中每個物件承擔的角色不同,但總的來說無非就是”資料的傳送者”或”資料的接收者”兩種角色。訊息的正向傳遞比較簡單,直接拿到接受者的指標即可。訊息的反響傳遞可以通過委託模式,觀察者模式(本質是單例模式),block語法,AppDelegagte來實現。其中委託模式,block語法都是1對1的訊息傳遞。 觀察者模式是1對多。AppDelegate比較特殊,這是一個生命週期與程序一致的物件。 8. 什麼叫資料結構?
資料結構是計算機儲存、組織資料的方式。是指相互之間存在一種或多種特定關係的資料元素的集合。通常,精心選擇的資料結構可以帶來更高的執行或者儲存效率。 9. OC的類可以多繼承嗎?可以實現多個介面嗎?Category是什麼?分類中能定義成員變數或屬性嗎?為什麼?重寫一個類的方式是繼承好還是類別好?為什麼?
Object-c的類不可以多重繼承;可以實現多個介面(協議),通過實現多個介面可以完成C++的多重繼承;Category是類別,推薦使用類別,用Category去重寫類的方法,僅對本引入Category的類有效,不會影響到其他類與原有類的關係。 10. #import和#include有什麼區別?@class呢?#import<>和#import”“有什麼區別?*
import是Objective-C匯入標頭檔案的關鍵字,#include是C/C++匯入標頭檔案的關鍵字,使用#import標頭檔案會自動只匯入一次,不會重複匯入,相當於#include和#pragma once;@class告訴編譯器某個類的宣告,當執行時,才去檢視類的實現檔案,可以解決標頭檔案的相互包含;#import<>用來包含系統的標頭檔案,#import””用來包含使用者標頭檔案。例如:/ 如果這裡不寫@class,則報錯。 原因是找不到MyVC的定義。因為程式碼執行順序是由上至下的。當宣告協議MyVCDelegate時, MyVC還沒有宣告。使用 @class 名稱隨便寫,不管是否存在。 可以自己用程式碼嘗試隨意寫個@class 例如:@class Hello; 就算專案中根本沒有Hello類,這裡也不會報錯。 因為只有當專案執行起來,才會真的去檢查Hello類是否聲明瞭。/@class MyVC;@protocol MyVCDelegate- (void)myVC:(MyVC *)myVC click:(id)sender;
@end
@interface MyVC : BaseVC
@end
ps:iOS7之後的新特性,可以使用@import 關鍵詞來代理#import引入系統類庫。
使用@import引入系統類庫,不需要到build phases中先新增新增系統庫到專案中。
11.屬性readwrite, readonly, assign, retain, copy, nonatomic各是什麼作用?在哪種情況下用?
1.readwrite 是可讀可寫特性;需要生成getter方法和setter方法時
(補充:預設屬性,將生成不帶額外引數的getter和setter方法(setter方法只有一個引數))
2.readonly 是隻讀特性,只會生成getter方法,不會生成setter方法;不希望屬性在類外改變
3.assign 是賦值特性,setter方法將傳入引數賦值給例項變數;僅設定變數時;
4.retain(MRC)/strong(ARC) 表示持有特性,setter方法將傳入引數先保留,
再賦值,傳入引數的retaincount會+1;
5.copy 表示拷貝特性,setter方法將傳入物件複製一份;需要完全一份新的變數時。
6.nonatomic 非原子操作,決定編譯器生成的setter和getter方法是否是原子操作。
atomic表示多執行緒安全,需要對方法加鎖,保證同一時間只有一個執行緒訪問屬性,
因為有等待過程,所以影響執行效率
一般使用nonatomic。不加鎖。效率會更高。但是執行緒不安全。
12. 寫一個setter方法用於完成@property(nonatomic, strong)NSString name, 寫一個setter方法用於完成@property(nonatomic, copy)NSString name
(void)setName:(NSString*)str //retain
{
[str retain];
[_name release];
_name = str;
}
(void)setName:(NSString )str //copy
{
id t = [str copy];
[_name release];
_name = t;
}
*13. 對於語句NSString obj = [[NSData alloc] init]; obj在編譯時和執行時分別是什麼型別的物件?
編譯時是NSString的型別;執行時是NSData型別的物件。 14. 常見的OC的資料型別有哪些? 和C的基本資料型別有什麼區別? 如:NSInteger和int*
object-c的資料型別有NSString,NSNumber,NSArray,NSMutableArray,NSData等等。
C語言的基本資料型別int,只是一定位元組的記憶體空間,用於存放數值;
NSInteger型別的定義是
if LP64 || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE)
|| TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
else
typedef int NSInteger;
typedef unsigned int NSUInteger;
endif
可以看到,在64位作業系統上,NSInteger是 C語言的long型別。
在32位作業系統上,則是int型別。
15. id宣告的物件有什麼特性?
id 宣告的物件具有執行時的特性,即可以指向任意型別的objcetive-c的物件;
可以作為返回值,也可以宣告物件。
例如
(id)initWithName:(NSString *)name;
id obj = [NSObject new];
現在我們使用蘋果推薦使用的“instancetype”型別代替id型別作為返回值
(instancetype)initWithName:(NSString )name;
instancetype和id的區別在於, id可以宣告物件 也可以作為返回值,
instancetype只能作為返回值。
*16. OC如何對記憶體管理的,說說你的看法和解決方法。
Objective-C的記憶體管理主要有三種方式ARC(自動記憶體計數)、手動記憶體計數、記憶體池。
自動記憶體計數ARC:由Xcode自動在App編譯階段,在程式碼中新增記憶體管理程式碼。
手動記憶體計數MRC:遵循記憶體誰申請,誰新增。誰釋放的原則。
記憶體釋放池Release Pool:把需要釋放的記憶體統一放在一個池子中,當池子被抽乾後(drain)
池子中所有的記憶體空間也被自動釋放掉。 記憶體池的釋放操作分為自動和手動。
自動釋放受runloop機制影響。
17. 你對@interface中的成員變數和@property宣告的屬性的理解。
@interface AA: NSObject{
NSString _name; //成員變數
}
@property NSString sex; //屬性
如上所示:
屬性擁有setter和getter方法 外加_sex成員變數。
_name只是成員變數, 沒有setter和getter方法。
18. do while 和while do的區別?
while do是先判斷while中的表示式的真假,再執行迴圈。
do while先進行迴圈一次,再判斷while中的表示式的真假。
19. 用預處理指令#define宣告一個常數,用以表明一年中有多少秒(忽略閏年問題)。
define SECONDS_PER_YEAR (60 60 24 * 365)
20. 淺拷貝和深拷貝的區別?
淺拷貝:只複製指向物件的指標,而不復制引用物件本身。
深拷貝:複製引用和物件本身。
意思就是說我有個A物件,複製一份後得到A_copy物件後,
對於淺複製來說,A和A_copy指向的是同一個記憶體資源,複製的只不過是是一個指標,
物件本身資源還是隻有一份。
那如果我們對A_copy執行了修改操作,那麼發現A引用的物件同樣被修改,
這其實違背了我們複製拷貝的一個思想。
深複製就好理解了,記憶體中存在了兩份獨立物件本身。
用網上一哥們通俗的話將就是:
淺拷貝好比你和你的影子,你完蛋,你的影子也完蛋
深拷貝好比你和你的克隆人,你完蛋,你的克隆人還活著。
21. 類別的作用?繼承和類別在實現中有何區別?
Category可以向類中新增新的方法,或者重寫已有方法。
正常情況下不可以新增屬性。但是實際應用中可以通過runtime機制新增屬性。
類別主要有3個作用:
將類的實現分散到多個不同檔案或多個不同框架中。降低耦合性。
重寫主類方法
向類中新增協議,屬性,方法。
繼承主要作用:
重寫父類方法
在父類基礎上增加屬性,方法,協議
區別:繼承使用時,需要使用子類。 Category使用時只需要引入標頭檔案。
22. 我們說的OC是動態執行時語言是什麼意思?
編譯時等價於編碼時, 編碼時就是程式設計師寫的程式碼的樣子. 程式設計師為一個類編寫程式碼,
便可以為一個類新增 “成員變數(例項變數)” . 程式設計師也可以在一個類中寫一些函式, 被稱作“方法”.
執行前編譯, 編譯器會把程式設計師寫的程式碼編譯成可執行檔案, 裡面便有之前寫的類的資訊,
包括例項變數和方法, 這些資訊並不能組成一個實際的資料型別.
程式執行後, 會將這些資訊拼湊成一個結構體, 這個結構體便是一個數據型別.
同時, 在執行期間, 資料型別可以改變, 表現為:
可以動態增添方法
可以動態增添例項變數
等等..做一些執行時資料型別修改.
一旦做了執行時修改, 就會使得這個結構體與程式設計師當初編寫的類不一樣.
23. 為什麼很多內建類如UITableView的delegate屬性都是assign而不是retain ?
如果是retain會引起迴圈引用。
所有的引用計數系統,都存在迴圈引用的問題。例如下面的引用關係:
物件a建立並引用了物件b,物件b建立並引用了物件c,物件c建立並引用了物件b.
這時候b和c的引用計數分別是2和1。當a不再使用b,呼叫release釋放對b的所有權,因為c還引用了b。
所以b的引用計數為1,b不會被釋放。b不釋放,c的引用計數就是1,c也不會被釋放。
從此,b和c永遠留在記憶體中。
這種情況,必須打斷迴圈引用,通過其他規則來維護引用關係。
比如,我們常見的delegate往往是assign方式的屬性而不是retain方式的屬性,
賦值不會增加引用計數,就是為了防止delegation兩端產生不必要的迴圈引用。
如果一個UITableViewController物件a通過retain獲取了UITableView物件b的所有權,
這個UITableView物件b的delegate又是a,如果這個delegate是retain方式的,
那基本上就沒有機會釋放這兩個物件了。
24. 什麼時候用delegate,什麼時候用Notification?
Delegate(委託模式):
1對1的反向訊息通知功能。
Notification(通知模式):
只想要把訊息傳送出去,告知某些狀態的變化。但是並不關心誰想要知道這個。
25. 什麼是KVC和KVO?
KVC(Key-Value-Coding):鍵 - 值編碼是一種通過字串間接訪問物件的方式。
而不是通過呼叫setter方法或通過例項變數訪問的機制。很多情況下可以簡化程式程式碼。
例如:
@interface MeiLing:NSObject
@property NSString name;
@property UILabel label;
@end
對於name的賦值 可以使用 meiLing.name = @"笑玲"; 這是點語法。呼叫的是setName方法。
KVC的寫法是 [meiLing setValue:@"夢玲" forKey:@"name"]; 通過name字串賦值。
當然也可以跨層賦值,例如為label的text屬性賦值
點語法: meiLing.label.text = @"笑玲";
KVC: [meiLing setValue:@"夢玲" forKeyPath:@"label.text"];
KVO:鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了程式碼。
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
*26. 設計模式是什麼?你知道哪些設計模式,並簡要敘述。
單例模式:通過static關鍵詞,宣告全域性變數。在整個程序執行期間只會被賦值一次。
觀察者模式:KVO是典型的通知模式,觀察某個屬性的狀態,狀態發生變化時通知觀察者。
委託模式:代理+協議的組合。實現1對1的反相傳值操作。
工廠模式:通過一個類方法,批量的根據已有模板生產物件。
MVC模式:Model View Control, 把模型 檢視 控制器 層進行解耦合編寫。
MVVM模式:Model View ViewModel 把 模型 檢視 業務邏輯 層進行解耦合編寫。
27. 描述一下iOS SDK中如何實現MVC的開發模式。
MVC即 Model-View-Control
Model稱為模型層,主要負責資料結構,業務邏輯相關的操作
View 稱為檢視層,主要負責檢視的展示
Control 稱為控制層,主要負責把View和Model層結合起來的操作。例如點選檢視上的某個按鈕
要執行Model層中的某個業務邏輯。 或者把Model中的資料展現在檢視上。
28. ViewController的didReceiveMemoryWarning是在什麼時候呼叫的?預設的操作是什麼?
當系統記憶體不足時,首先UIViewController的didReceiveMemoryWarining方法會被呼叫。
預設操作如果當前控制器不是window的根檢視控制器,會自動將self.view釋放。
29. delegate和Block的區別?
delegate:
需要定義協議方法並且實現協議方法,會使程式碼結構變複雜
效率沒有block高
block:
程式碼結構更加緊湊,不需要額外定義方法。
需要注意防止迴圈引用,使用__weak 關鍵詞修飾
當需要在塊中修改外部變數時,需要對外部變數使用__block 關鍵詞修飾
30. frame和bounds有什麼不同?
frame指的是:該view在父view座標系統中的位置和大小。(參照點是父親的座標系統)
bounds指的是:該view在本身座標系統中 的位置和大小。(參照點是本身座標系統)
31.ViewController生命週期
按照執行順序排列
initWithCoder:通過nib檔案初始化時觸發
awakeFromNib:nib檔案被載入的時候,會發送一個awakeFromNib的訊息到nib檔案中的每個物件
loadView:開始載入檢視控制器自帶的view
viewDidLoad:檢視控制器的view被載入完成
viewWillAppear:檢視控制器的view將要顯示在window上
updateViewConstraints:檢視控制器的view開始更新AutoLayout約束
viewWillLayoutSubviews:檢視控制器的view將要更新內容檢視的位置
viewDidLayoutSubviews:檢視控制器的view已經更新檢視的位置
viewDidAppear:檢視控制器的view已經展現到window上
viewWillDisappear:檢視控制器的view將要從window上消失
viewDidDisappear:檢視控制器的view已經從window上消失
32. 如何將產品進行多語言釋出,開發?
國際化操作
在Xcode中,Project裡,找到Localization,點選+號,新增想要支援的語言
通過新建Strings檔案,把檔案進行國際化處理。 通過鍵值對的形式,同一個key在不同的國際化
檔案中,對應不同的值。
通過 NSLocalizedStringFromTable 等方法,通過key來自動根據iOS裝置的當前語言,
顯示不同的字串。
33. OC中是如何實現執行緒同步的?
@synchronized: 新增同步鎖
NSLock:加鎖
NSCondition:加條件鎖
dispatch_async(dispatch_get_main_queue(), ^{}); :非同步主執行緒
NSOperationQueue:新增執行緒依賴
NSOperationQueue:設定最大併發數為1
34. UDP和TCP的區別是什麼?
1.基於連線與無連線;
2.對系統資源的要求(TCP較多,UDP少);
3.UDP程式結構較簡單;
4.流模式與資料報模式 ;
5.TCP保證資料正確性,UDP可能丟包,TCP保證資料順序,UDP不保證
35. TCP/IP建立連線的過程?
在TCP/IP 協議中,TCP協議提供可靠的連線服務,採用三次握手建立連線;
第一次握手:建立連線時,客戶端傳送連線請求到伺服器,並進入SYN_SEND狀態,等待伺服器確認;
第二次握手:伺服器收到客戶端連線請求,向客戶端傳送允許連線應答,
此時伺服器進入SYN_RECV狀態;
第三次握手:客戶端收到伺服器的允許連線應答,向伺服器傳送確認,客戶端和伺服器進入通訊狀態,
完成三次握手。
(所謂的三次握手,就是要有三次連線資訊的傳送、接收過程。
TCP連的建立需要進行三次連線資訊的傳送、接收。)
36. 程式設計中,儲存資料有哪幾種方式?
資料:Sqlite。 操作方式分為原生的sqlite3,FMDB,Coredata
歸檔:Archive。 自定義型別需要注意遵循NSCoding協議
Plist:就是陣列或字典,寫入檔案後的表現形式。
NSUserDefault:本質上就是Plist。
寫檔案
上傳到伺服器
37. 介紹版本控制中Git與SVN。
1、Git是一款免費、開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的專案。
主要區別於SVN工具的功能是 分支功能比SVN強大。 (常用)
2、SVN是Subversion的簡稱,是一個開放原始碼的版本控制系統,它採用了分支管理系統,
它的設計目標就是取代CVS。
38. OC中建立執行緒的方法是什麼?如果在主執行緒中執行程式碼,方法是什麼?如果想延時執行程式碼,方法又是什麼?
建立執行緒的方法
[NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
[self performSelectorInBackground:nil withObject:nil];
[[NSThread alloc] initWithTarget:nil selector:nil object:nil];
dispatch_async(dispatch_get_global_queue(0, 0), ^{});
[[NSOperationQueue new] addOperation:nil];
主執行緒中執行程式碼的方法
[self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES]
dispatch_async(dispatch_get_main_queue(), ^{});
[[NSOperationQueue mainQueue] addOperation:nil];
延遲執行程式碼
sleep(2) 睡兩秒鐘
NSTimer啟動定時器
39. iOS中有哪些多執行緒方案?
常用的有三種: NSThread NSOperationQueue GCD。
1、NSThread 是這三種正規化裡面相對輕量級的,但也是使用起來最負責的,
你需要自己管理thread的生命週期,執行緒之間的同步。執行緒共享同一應用程式的部分記憶體空間,
它們擁有對資料相同的訪問許可權。你得協調多個執行緒對同一資料的訪問,
一般做法是在訪問之前加鎖,這會導致一定的效能開銷。
2、NSOperationQueue 以面向物件的方式封裝了使用者需要執行的操作,
我們只要聚焦於我們需要做的事情,而不必太操心執行緒的管理,同步等事情,
因為NSOperation已經為我們封裝了這些事情。
NSOperation 是一個抽象基類,我們必須使用它的子類。
3、 GCD: iOS4 才開始支援,它提供了一些新的特性,以及執行庫來支援多核並行程式設計,
它的關注點更高:如何在多個cpu上提升效率。
總結:
NSThread是早期的多執行緒解決方案,實際上是把C語言的PThread執行緒管理程式碼封裝成OC程式碼。
GCD是取代NSThread的多執行緒技術,C語法+block。功能強大。
NSOperationQueue是把GCD封裝為OC語法,額外比GCD增加了幾項新功能。
最大執行緒併發數
取消佇列中的任務
暫停佇列中的任務
可以調整佇列中的任務執行順序,通過優先順序
執行緒依賴
NSOperationQueue支援KVO。 這就意味著你可以觀察任務的狀態屬性。
但是NSOperationQueue的執行效率沒有GCD高,所以一半情況下,我們使用GCD來完成多執行緒操作。
40. 執行緒與程序的區別和聯絡?
1.什麼是程序
程序是指在系統中正在執行的一個應用程式
每個程序之間是獨立的,每個程序均執行在其專用且受保護的記憶體空間內
2.什麼是執行緒
1個程序要想執行任務,必須得有執行緒(每1個程序至少要有1條執行緒)
執行緒是程序的基本執行單元,一個程序(程式)的所有任務都線上程中執行。
MRC:手動記憶體釋放。遵循誰申請誰釋放的原則,需要手動的處理記憶體計數的增加和修改。從12年開始,逐步被ARC(自動記憶體釋放)模式取代。
點語法: “self.屬性 = obj” 呼叫屬性的setter方法。”self.屬性” 呼叫屬性的getter方法區別在於是否有等號。
41.Provider是指某個iPhone軟體的Push伺服器,這篇文章我將使用.net作為Provider。
APNS 是Apple Push Notification Service(Apple Push伺服器)的縮寫,是蘋果的伺服器。
上圖可以分為三個階段。
第一階段:.net應用程式把要傳送的訊息、目的iPhone的標識打包,發給APNS。
第二階段:APNS在自身的已註冊Push服務的iPhone列表中,查詢有相應標識的iPhone,並把訊息發到iPhone。
第三階段:iPhone把發來的訊息傳遞給相應的應用程式,並且按照設定彈出Push通知。
http://blog.csdn.net/zhuqilin0/article/details/6527113 //訊息推送機制
看記憶體洩露時候:在搜尋中搜索run 找到Run Static Analyzer .


42.ASIDownloadCache 設定下載快取
它對Get請求的響應資料進行快取(被快取的資料必需是成功的200請求):
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
當設定快取策略後,所有的請求都被自動的快取起來。
另外,如果僅僅希望某次請求使用快取操作,也可以這樣使用:
ASIHTTPRequest request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
快取儲存方式
你可以設定快取的資料需要儲存多長時間,ASIHTTPRequest提供了兩種策略:
a,ASICacheForSessionDurationCacheStoragePolicy,預設策略,基於session的快取資料儲存。當下次執行或[ASIHTTPRequest clearSession]時,快取將失效。
b,ASICachePermanentlyCacheStoragePolicy,把快取資料永久儲存在本地,
如:
ASIHTTPRequest request = [ ASIHTTPRequest requestWithURL:url ];
[ request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy ];
43.HTTP協議詳解
HTTP是一個屬於應用層的面向物件的協議,由於其簡捷、快速的方式,適用於分散式超媒體資訊系統。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的規範化工作正在進行之中。
http(超文字傳輸協議)是一個基於請求與響應模式的、無狀態的、應用層的協議,常基於TCP的連線方式,HTTP1.1版本中給出一種持續連線的機制,絕大多數的Web開發,都是構建在HTTP協議之上的Web應用。
HTTP協議的主要特點可概括如下:
1.支援客戶/伺服器模式。
2.簡單快速:客戶向伺服器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與伺服器聯絡的型別不同。由於HTTP協議簡單,使得HTTP伺服器的程式規模小,因而通訊速度很快。
3.靈活:HTTP允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。
4.無連線:無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。
5.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。
44.URL
HTTP URL (URL是一種特殊型別的URI是他的子類,包含了用於查詢某個資源的足夠的資訊)的格式如下:
http://host[":"port][abs_path]
http表示要通過HTTP協議來定位網路資源;host表示合法的Internet主機域名或者IP地址;port指定一個埠號,為空則使用預設埠80;abs_path指定請求資源的URI;如果URL中沒有給出abs_path,那麼當它作為請求URI時,必須以“/”的形式給出,通常這個工作瀏覽器自動幫我們完成。
45.TCP/UDP區別聯絡
TCP---傳輸控制協議,提供的是面向連線、可靠的位元組流服務。當客戶和伺服器彼此交換資料前,必須先在雙方之間建立一個TCP連線,之後才能傳輸資料。TCP提供超時重發,丟棄重複資料,檢驗資料,流量控制等功能,保證資料能從一端傳到另一端。
UDP---使用者資料報協議,是一個簡單的面向資料報的運輸層協議。UDP不提供可靠性,它只是把應用程式傳給IP層的資料報傳送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸資料報前不用在客戶和伺服器之間建立一個連線,且沒有超時重發等機制,故而傳輸速度很快
TCP(Transmission Control Protocol,傳輸控制協議)是基於連線的協議,也就是說,在正式收發資料前,必須和對方建立可靠的連線。一個TCP連線必須要經過三次“對話”才能建立起來,我們來看看這三次對話的簡單過程:1.主機A向主機B發出連線請求資料包;2.主機B向主機A傳送同意連線和要求同步(同步就是兩臺主機一個在傳送,一個在接收,協調工作)的資料包;3.主機A再發出一個數據包確認主機B的要求同步:“我現在就發,你接著吧!”,這是第三次對話。三次“對話”的目的是使資料包的傳送和接收同步,經過三次“對話”之後,主機A才向主機B正式傳送資料。
UDP(User Data Protocol,使用者資料報協議)是與TCP相對應的協議。它是面向非連線的協議,它不與對方建立連線,而是直接就把資料包傳送過去! UDP適用於一次只傳送少量資料、對可靠性要求不高的應用環境。
tcp協議和udp協議的差別
是否連接面向連接面向非連線
傳輸可靠性可靠不可靠
應用場合傳輸大量資料少量資料
速度慢快
46.socket連線和http連線的區別
簡單說,你瀏覽的網頁(網址以http://開頭)都是http協議傳輸到你的瀏覽器的, 而http是基於socket之上的。socket是一套完成tcp,udp協議的介面。
HTTP協議:簡單物件訪問協議,對應於應用層 ,HTTP協議是基於TCP連線的
tcp協議: 對應於傳輸層
ip協議: 對應於網路層
TCP/IP是傳輸層協議,主要解決資料如何在網路中傳輸;而HTTP是應用層協議,主要解決如何包裝資料。
Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個呼叫介面(API),通過Socket,我們才能使用TCP/IP協議。
http連線:http連線就是所謂的短連線,即客戶端向伺服器端傳送一次請求,伺服器端響應後連線即會斷掉;
socket連線:socket連線就是所謂的長連線,理論上客戶端和伺服器端一旦建立起連線將不會主動斷掉;但是由於各種環境因素可能會是連線斷開,比如說:伺服器端或客戶端主機down了,網路故障,或者兩者之間長時間沒有資料傳輸,網路防火牆可能會斷開該連線以釋放網路資源。所以當一個socket連線中沒有資料的傳輸,那麼為了維持連線需要傳送心跳訊息~~具體心跳訊息格式是開發者自己定義的
我們已經知道網路中的程序是通過socket來通訊的,那什麼是socket呢?socket起源於Unix,而Unix/Linux基本哲學之一就是“一切皆檔案”,都可以用“開啟open –> 讀寫write/read –> 關閉close”模式來操作。我的理解就是Socket就是該模式的一個實現,socket即是一種特殊的檔案,一些socket函式就是對其進行的操作(讀/寫IO、開啟、關閉),這些函式我們在後面進行介紹。我們在傳輸資料時,可以只使用(傳輸層)TCP/IP協議,但是那樣的話,如果沒有應用層,便無法識別資料內容,如果想要使傳輸的資料有意義,則必須使用到應用層協議,應用層協議有很多,比如HTTP、FTP、TELNET等,也可以自己定義應用層協議。WEB使用HTTP協議作應用層協議,以封裝HTTP文字資訊,然後使用TCP/IP做傳輸層協議將它發到網路上。
1)Socket是一個針對TCP和UDP程式設計的介面,你可以藉助它建立TCP連線等等。而TCP和UDP協議屬於傳輸層 。
而http是個應用層的協議,它實際上也建立在TCP協議之上。
(HTTP是轎車,提供了封裝或者顯示資料的具體形式;Socket是發動機,提供了網路通訊的能力。)
2)Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個呼叫介面(API),通過Socket,我們才能使用TCP/IP協議。Socket的出現只是使得程式設計師更方便地使用TCP/IP協議棧而已,是對TCP/IP協議的抽象,從而形成了我們知道的一些最基本的函式介面。
47.什麼是TCP連線的三次握手
第一次握手:客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀態,等待伺服器確認;
第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。
握手過程中傳送的包裡不包含資料,三次握手完畢後,客戶端與伺服器才正式開始傳送資料。理想狀態下,TCP連線一旦建立,在通訊雙方中的任何一方主動關閉連線之前,TCP 連線都將被一直保持下去。斷開連線時伺服器和客戶端均可以主動發起斷開TCP連線的請求,斷開過程需要經過“四次握手”(過程就不細寫了,就是伺服器和客戶端互動,最終確定斷開)
48.利用Socket建立網路連線的步驟
建立Socket連線至少需要一對套接字,其中一個運行於客戶端,稱為ClientSocket ,另一個運行於伺服器端,稱為ServerSocket 。
套接字之間的連線過程分為三個步驟:伺服器監聽,客戶端請求,連線確認。
1。伺服器監聽:伺服器端套接字並不定位具體的客戶端套接字,而是處於等待連線的狀態,實時監控網路狀態,等待客戶端的連線請求。
2。客戶端請求:指客戶端的套接字提出連線請求,要連線的目標是伺服器端的套接字。為此,客戶端的套接字必須首先描述它要連線的伺服器的套接字,指出伺服器端套接字的地址和埠號,然後就向伺服器端套接字提出連線請求。

3。連線確認:當伺服器端套接字監聽到或者說接收到客戶端套接字的連線請求時,就響應客戶端套接字的請求,建立一個新的執行緒,把伺服器端套接字的描述發給客戶端,一旦客戶端確認了此描述,雙方就正式建立連線。而伺服器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連線請求。

1.什麼是arc?(arc是為了解決什麼問題誕生的?)

首先解釋ARC: automatic reference counting自動引用計數。 
ARC幾個要點: 
在物件被建立時 retain count +1,在物件被release時 retain count -1.當retain count 為0 時,銷燬物件。 
程式中加入autoreleasepool的物件會由系統自動加上autorelease方法,如果該物件引用計數為0,則銷燬。 
那麼ARC是為了解決什麼問題誕生的呢?這個得追溯到MRC手動記憶體管理時代說起。 
MRC下記憶體管理的缺點: 
1.當我們要釋放一個堆記憶體時,首先要確定指向這個堆空間的指標都被release了。(避擴音前釋放) 
2.釋放指標指向的堆空間,首先要確定哪些指標指向同一個堆,這些指標只能釋放一次。(MRC下即誰建立,誰釋放,避免重複釋放) 
3.模組化操作時,物件可能被多個模組建立和使用,不能確定最後由誰去釋放。 
4.多執行緒操作時,不確定哪個執行緒最後使用完畢

2.請解釋以下keywords的區別: assign vs weak, __block vs __weak

assign適用於基本資料型別,weak是適用於NSObject物件,並且是一個弱引用。 
assign其實也可以用來修飾物件,那麼我們為什麼不用它呢?因為被assign修飾的物件在釋放之後,指標的地址還是存在的,也就是說指標並沒有被置為nil。如果在後續的記憶體分配中,剛好分到了這塊地址,程式就會崩潰掉。 
而weak修飾的物件在釋放之後,指標地址會被置為nil。所以現在一般弱引用就是用weak。 
首先__block是用來修飾一個變數,這個變數就可以在block中被修改(參考block實現原理) 
__block:使用__block修飾的變數在block程式碼快中會被retain(ARC下,MRC下不會retain) 
__weak:使用__weak修飾的變數不會在block程式碼塊中被retain 
同時,在ARC下,要避免block出現迴圈引用 __weak typedof(self)weakSelf = self;

3.__block在arc和非arc下含義一樣嗎?

是不一樣的。 
在MRC中__block variable在block中使用是不會retain的 
但是ARC中__block則是會Retain的。 
取而代之的是用__weak或是__unsafe_unretained來更精確的描述weak reference的目的 
其中前者只能在iOS5之後可以使用,但是比較好 (該物件release之後,此pointer會自動設成nil) 
而後者是ARC的環境下為了相容4.x的解決方案。 
所以上面的範例中

 __block MyClass* temp = …;    // MRC環境下使用
 __weak MyClass* temp = …;    // ARC但只支援iOS5.0以上的版本
 __unsafe_retained MyClass* temp = …;  //ARC且可以相容4.x以後的版本

4.使用nonatomic一定是執行緒安全的嗎?()

不是的。 
atomic原子操作,系統會為setter方法加鎖。 具體使用 @synchronized(self){//code } 
nonatomic不會為setter方法加鎖。 
atomic:執行緒安全,需要消耗大量系統資源來為屬性加鎖 
nonatomic:非執行緒安全,適合記憶體較小的移動裝置

5.描述一個你遇到過的retain cycle例子。

block中的迴圈引用:一個viewController

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@property</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">nonatomic</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">strong</span>)HttpRequestHandler * handler;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">@property</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">nonatomic</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">strong</span>)NSData          *data;
    _handler = [httpRequestHandler sharedManager];
    [ downloadData:^(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> responseData){
        _data = responseData;
    }];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

self 擁有_handler, _handler 擁有block, block擁有self(因為使用了self的_data屬性,block會copy 一份self) 
解決方法:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    __<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">weak</span> typedof(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>)weakSelf = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>
    [ downloadData:^(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> responseData){
        weakSelf<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.data</span> = responseData;
    }];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

6.+(void)load; +(void)initialize;有什麼用處?

在Objective-C中,runtime會自動呼叫每個類的兩個方法。+load會在類初始載入時呼叫,+initialize會在第一次呼叫類的類方法或例項方法之前被呼叫。這兩個方法是可選的,且只有在實現了它們時才會被呼叫。 
共同點:兩個方法都只會被呼叫一次。

7.為什麼其他語言裡叫函式呼叫, objective c裡則是給物件發訊息(或者談下對runtime的理解)

先來看看怎麼理解發送訊息的含義:

曾經覺得Objc特別方便上手,面對著 Cocoa 中大量 API,只知道簡單的查文件和呼叫。還記得初學 Objective-C 時把[receiver message]當成簡單的方法呼叫,而無視了“傳送訊息”這句話的深刻含義。於是[receiver message]會被編譯器轉化為: 
objc_msgSend(receiver, selector) 
如果訊息含有引數,則為: 
objc_msgSend(receiver, selector, arg1, arg2, ...)

如果訊息的接收者能夠找到對應的selector,那麼就相當於直接執行了接收者這個物件的特定方法;否則,訊息要麼被轉發,或是臨時向接收者動態新增這個selector對應的實現內容,要麼就乾脆玩完崩潰掉。

現在可以看出[receiver message]真的不是一個簡簡單單的方法呼叫。因為這只是在編譯階段確定了要向接收者傳送message這條訊息,而receive將要如何響應這條訊息,那就要看執行時發生的情況來決定了。

Objective-C 的 Runtime 鑄就了它動態語言的特性,這些深層次的知識雖然平時寫程式碼用的少一些,但是卻是每個 Objc 程式設計師需要了解的。

Objc Runtime使得C具有了面向物件能力,在程式執行時建立,檢查,修改類、物件和它們的方法。可以使用runtime的一系列方法實現。

順便附上OC中一個類的資料結構 /usr/include/objc/runtime.h

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">   <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> objc_class {
    Class isa OBJC_ISA_AVAILABILITY; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//isa指標指向Meta Class,因為Objc的類的本身也是一個Object,為了處理這個關係,r       untime就創造了Meta Class,當給類傳送[NSObject alloc]這樣訊息時,實際上是把這個訊息發給了Class Object</span>

    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">if</span> !__OBJC2__</span>
    Class super_class OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 父類</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *name OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 類名</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> version OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 類的版本資訊,預設為0</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> info OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 類資訊,供執行期使用的一些位標識</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> instance_size OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 該類的例項變數大小</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> objc_ivar_list *ivars OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 該類的成員變數連結串列</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> objc_method_list **methodLists OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 方法定義的連結串列</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> objc_cache *cache OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 方法快取,物件接到一個訊息會根據isa指標查詢訊息物件,這時會在method       Lists中遍歷,如果cache了,常用的方法呼叫時就能夠提高呼叫的效率。</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">struct</span> objc_protocol_list *protocols OBJC2_UNAVAILABLE; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 協議連結串列</span>
    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">endif</span></span>

    } OBJC2_UNAVAILABLE;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

OC中一個類的物件例項的資料結構(/usr/include/objc/objc.h):

<code class="hljs scala has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    typedef struct objc_<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> *<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Class</span>;</span>

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/// Represents an instance of a class.</span>

    struct objc_<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">object</span> {</span>

        Class isa  OBJC_ISA_AVAILABILITY;

    };

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/// A pointer to an instance of a class.</span>

    typedef struct objc_<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">object</span> *<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">id</span>;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

向object傳送訊息時,Runtime庫會根據object的isa指標找到這個例項object所屬於的類,然後在類的方法列表以及父類方法列表尋找對應的方法執行。id是一個objc_object結構型別的指標,這個型別的物件能夠轉換成任何一種物件。

然後再來看看訊息傳送的函式:objc_msgSend函式

在引言中已經對objc_msgSend進行了一點介紹,看起來像是objc_msgSend返回了資料,其實objc_msgSend從不返回資料而是你的方法被呼叫後返回了資料。下面詳細敘述下訊息傳送步驟:

檢測這個 selector 是不是要忽略的。比如 Mac OS X 開發,有了垃圾回收就不理會 retain,release 這些函數了。 
檢測這個 target 是不是 nil 物件。ObjC 的特性是允許對一個 nil 物件執行任何一個方法不會 Crash,因為會被忽略掉。 
如果上面兩個都過了,那就開始查詢這個類的 IMP,先從 cache 裡面找,完了找得到就跳到對應的函式去執行。 
如果 cache 找不到就找一下方法分發表。 
如果分發表找不到就到超類的分發表去找,一直找,直到找到NSObject類為止。 
如果還找不到就要開始進入動態方法解析了,後面會提到。

後面還有: 
動態方法解析resolveThisMethodDynamically 
訊息轉發forwardingTargetForSelector

8.什麼是method swizzling?

Method Swizzling 原理(方法攪拌?)

在Objective-C中呼叫一個方法,其實是向一個物件傳送訊息,查詢訊息的唯一依據是selector的名字。利用Objective-C的動態特性,可以實現在執行時偷換selector對應的方法實現,達到給方法掛鉤的目的。 
每個類都有一個方法列表,存放著selector的名字和方法實現的對映關係。IMP有點類似函式指標,指向具體的Method實現。

方法指向

我們可以利用 method_exchangeImplementations 來交換2個方法中的IMP,

我們可以利用 class_replaceMethod 來修改類,

我們可以利用 method_setImplementation 來直接設定某個方法的IMP, 
…… 
歸根結底,都是偷換了selector的IMP,如下圖所示: 
方法交換

9.UIView和CALayer是啥關係?

1.UIView是iOS系統中介面元素的基礎,所有的介面元素都繼承自它。它本身完全是由CoreAnimation來實現的 (Mac下似乎不是這樣)。它真正的繪圖部分,是由一個叫CALayer(Core Animation Layer)的類來管理。 UIView本身,更像是一個CALayer的管理器,訪問它的跟繪圖和跟座標有關的屬性,例如frame,bounds等 等,實際上內部都是在訪問它所包含的CALayer的相關屬性。

2.UIView有個layer屬性,可以返回它的主CALayer例項,UIView有一個layerClass方法,返回主layer所使用的 類,UIView的子類,可以通過過載這個方法,來讓UIView使用不同的CALayer來顯示,例如通過

<code class="hljs ruby has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">    - (<span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span>) <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">layerClass</span> {</span>

         <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ([<span class="hljs-constant" style="box-sizing: border-box;">CAEAGLLayer</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span>]);</span>
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><