上面一篇文章講了OC對象的本質(zhì)豪硅,編譯成C++對象是以什么形式存儲的串纺,一個對象占多少內(nèi)存空間等問題丽旅,那么在OC語言里面,又分為幾種對象呢纺棺?其實(shí)平時的工作中通過[[NSObject alloc] init]這種形式創(chuàng)建的對象都是實(shí)例對象榄笙,另外還有兩類平時接觸甚少的對象,一個是類對象祷蝌,一個就是元類對象茅撞。
開篇引題 類對象分為三種:
實(shí)例對象
類對象
元類對象
這三中類型的對象之間是什么關(guān)系?每種類型的對象又有什么特點(diǎn)呢?
開始一探究竟
- 實(shí)例對象
實(shí)現(xiàn)以下代碼
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
NSLog(@"%p %p",
object1,
object2);
打酉绯帷:0x100648340 0x100647440
總結(jié):不多講了鳞疲,第一篇文章已經(jīng)寫的很詳細(xì),
object1蠕蚜、object2是NSObject的instance對象(實(shí)例對象)
它們是不同的兩個對象尚洽,分別占據(jù)著兩塊不同的內(nèi)存
instance對象在內(nèi)存中存儲的信息包括
isa指針
其他成員變量
存儲的是各個成員變量的值,還有一個isa指針,一個類在內(nèi)存中的實(shí)例對象可以有多個靶累。
內(nèi)存存儲圖示
- 類對象
1.獲取類對象
兩種方法
NSObject *object1 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
還可以通過一個runtime函數(shù)
NSObject *object1 = [[NSObject alloc] init];
Class objectClass3 = object_getClass(object1);
object_getClass 函數(shù):傳入實(shí)例對象返回類對象腺毫,傳入類對象,返回元類對象
下面實(shí)現(xiàn)以下代碼
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
NSLog(@"%p %p",
object1,
object2);
NSLog(@"%p %p %p %p %p",
objectClass1,
objectClass2,
objectClass3,
objectClass4,
objectClass5);
打诱跫怼:0x100648340 0x100647440
0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118 0x7fff9dab4118
會發(fā)現(xiàn)兩個實(shí)例對象的內(nèi)存地址是不一樣的潮酒,而通過兩個實(shí)例對象獲得的5個類對象的指針都是一樣的,說明邪蛔,一個類在內(nèi)存中只有一個類對象急黎。
總結(jié):
objectClass1 ~ objectClass5都是NSObject的class對象(類對象)
它們是同一個對象。每個類在內(nèi)存中有且只有一個class對象
class對象在內(nèi)存中存儲的信息主要包括
isa指針
superclass指針
類的屬性信息(@property)侧到、類的對象方法信息(instance method)
類的協(xié)議信息(protocol)勃教、類的成員變量信息(ivar)
......
內(nèi)存存儲圖示
- 元類對象
執(zhí)行以下代碼獲取元類對象
// object_getClass 函數(shù):傳入實(shí)例對象返回類對象,傳入類對象匠抗,返回元類對象
Class objectClass3 = object_getClass([NSObject class]);
總結(jié):
objectMetaClass是NSObject的meta-class對象(元類對象)
每個類在內(nèi)存中有且只有一個meta-class對象
meta-class對象和class對象的內(nèi)存結(jié)構(gòu)是一樣的故源,但是用途不一樣,在內(nèi)存中存儲的信息主要包括
isa指針
superclass指針
類的類方法信息(class method)
......
關(guān)于如何證明剛剛所總結(jié)的三種類型的對象分別存儲的什么信息汞贸,通過閱讀蘋果源碼可知
分析:實(shí)例對象绳军,類對象和元類對象中都有isa指針,而類對象和元類對象中除了含有isa指針之外還有superclass指針矢腻,問題:isa指針和superclass指針分別有什么作用呢门驾?
- 分析 創(chuàng)建一個Person類給person類分別聲明一個對象方法和一個類方法
// Person
@interface Person : NSObject <NSCopying>
{
@public
int _age;
}
@property (nonatomic, assign) int no;
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personInstanceMethod{
}
+ (void)personClassMethod{
}
@end
// 調(diào)用
Person *person = [[Person alloc] init];
[person personInstanceMethod];
[Person personClassMethod];
-
isa指針作用
OC語言是消息機(jī)制 當(dāng)執(zhí)行[person personInstanceMethod]; 這行代碼時 實(shí)際會被編譯成 objc_msgSend(person, @selector(personInstanceMethod))進(jìn)行調(diào)用,那么剛剛說到實(shí)例對象中不存儲方法踏堡,那么當(dāng)調(diào)用時這個對象方法是怎么獲得的呢猎唁?
答案: 當(dāng)實(shí)例對象調(diào)用對象方法時是通過isa指針,指向自己的類對象顷蟆,找到類對象中的方法信息诫隅,進(jìn)行調(diào)用。同理帐偎,當(dāng)執(zhí)行 [Person personClassMethod]; 這行代碼時逐纬,實(shí)例對象通過isa指針指向自己的類對象,又通過類對象中的isa指針指向元類對象削樊,獲取到類方法信息豁生。
圖示:
創(chuàng)建一個Person類給person類分別聲明一個對象方法和一個類方法,再創(chuàng)建一個繼承于Person類的Student類給Student類分別聲明一個對象方法和一個類方法
// Person
@interface Person : NSObject <NSCopying>
{
@public
int _age;
}
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personInstanceMethod
{
}
+ (void)personClassMethod
{
}
@end
// Student
@interface Student : Person <NSCoding>
{
@public
int _weight;
}
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation MJStudent
- (void)studentInstanceMethod
{
}
+ (void)studentClassMethod
{
}
@end
// 調(diào)用
Student *student = [[Student alloc] init];
[student personInstanceMethod];
[Student personClassMethod];
- superclass指針作用
總結(jié):當(dāng)執(zhí)行[student personInstanceMethod]這行代碼時 student對象通過isa指針找到自己類對象兔毒,結(jié)果發(fā)現(xiàn)類對象中沒有personInstanceMethod這個方法,然后利用superclass指針找到父類也就是Person的類對象甸箱,查看是否有 personInstanceMethod 方法信息育叁,如果有 就調(diào)用,沒有的話繼續(xù)向上查找芍殖。同理:當(dāng)執(zhí)行[Student personClassMethod]; 這行代碼時豪嗽,student對象通過isa指針找到自己類對象,又通過類對象的isa指針找到自己的元類對象結(jié)果發(fā)現(xiàn)元類對象中沒有personClassMethod這個方法豌骏,元類對象利用superclass指針向上逐級尋找父類的元類對象是否有此方法龟梦。直到NSobject停止,如果找到就調(diào)用窃躲,找不到就會奔潰 unrecognized selector sent to class 0x1000011a0'
圖示:
最后總結(jié):
instance -> 實(shí)例對象计贰,class -> 類對象,meta-class -> 元類對象
1.instance的isa指向class
2.class的isa指向meta-class
3.meta-class的isa指向基類的meta-class
4.class的superclass指向父類的class
5.如果沒有父類蒂窒,superclass指針為nil
6.meta-class的superclass指向父類的meta-class
7.基類的meta-class的superclass指向基類的class
8.instance調(diào)用對象方法的軌跡
9.isa找到class躁倒,方法不存在,就通過superclass找父類
10.class調(diào)用類方法的軌跡
11.isa找meta-class刘绣,方法不存在樱溉,就通過superclass找父類
圖示:
-
畫一下[student personInstanceMethod]這行代碼的執(zhí)行順序
-
畫一下[Student load]這行代碼的執(zhí)行順序
疑問?纬凤??類方法再調(diào)用時先去自己的元類對象中尋找撩嚼,如果沒有就去父類的元類對象中尋找停士,在沒有就去NSObject的元類對象中尋找,再就去NSObject的類對象中尋找(根據(jù)最上面的線可以看來)那是這么回事嗎完丽?下面來驗(yàn)證一下
//新建一個Car類恋技,繼承自NSObject
@interface Car : NSObject
@end
@implementation Car
@end
// 創(chuàng)建一個NSObject的類別
//.h中代碼
+ (void)test;
//.m中代碼
+ (void)test{
NSLog(@"+[NSObject test] - %p", self);
}
//調(diào)用代碼
[Car test];
輸出 :[Car class] - 0x100001220
別的代碼都不變,將類別中.m中的代碼改成
//+號變成-號
- (void)test{
NSLog(@"+[NSObject test] - %p", self);
}
輸出 :[Car class] - 0x100001220
再調(diào)用發(fā)現(xiàn)還是可以成功逻族,具體的原因吧蜻底,我也說的不是很好,就不誤導(dǎo)別人了聘鳞,如果有大神知曉薄辅,歡迎指正
如有疑問歡迎指正~
強(qiáng)烈推薦:
iOS OC對象的本質(zhì)窺探(一)
iOS獲取手機(jī)唯一標(biāo)示
iOS 高德地圖實(shí)現(xiàn)大頭針展示,分級大頭針抠璃,自定制大頭針站楚,在地圖上畫線,線和點(diǎn)共存搏嗡,路線規(guī)劃(駕車路線規(guī)劃)窿春,路線導(dǎo)航拉一,等一些常見的使用場景