上面一篇文章講了OC對象的本質,編譯成C++對象是以什麼形式存儲的,一個對象占多少記憶體空間等問題,那麼在OC語言裡面,又分為幾種對象呢?其實平時的工作中通過[[NSObject alloc] init]這種形式建立的對象都是執行個體對象,另外還有兩類平時接觸甚少的對象,一個是類對象,一個就是元類對象。
開篇引題 類對象分為三種:
執行個體對象
類對象
元類對象
這三中類型的對象之間是什麼關系?每種類型的對象又有什麼特點呢?
開始一探究竟
-
執行個體對象
實作以下代碼
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
NSLog(@"%p %p",
object1,
object2);
列印:0x100648340 0x100647440
總結:不多講了,第一篇文章已經寫的很詳細,
object1、object2是NSObject的instance對象(執行個體對象)
它們是不同的兩個對象,分别占據着兩塊不同的記憶體
instance對象在記憶體中存儲的資訊包括
isa指針
其他成員變量
存儲的是各個成員變量的值,還有一個isa指針,一個類在記憶體中的執行個體對象可以有多個。
記憶體存儲圖示

-
類對象
1.擷取類對象
兩種方法
NSObject *object1 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
還可以通過一個runtime函數
NSObject *object1 = [[NSObject alloc] init];
Class objectClass3 = object_getClass(object1);
object_getClass 函數:傳入執行個體對象傳回類對象,傳入類對象,傳回元類對象
下面實作以下代碼
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
會發現兩個執行個體對象的記憶體位址是不一樣的,而通過兩個執行個體對象獲得的5個類對象的指針都是一樣的,說明,一個類在記憶體中隻有一個類對象。
先總結:
objectClass1 ~ objectClass5都是NSObject的class對象(類對象)
它們是同一個對象。每個類在記憶體中有且隻有一個class對象
class對象在記憶體中存儲的資訊主要包括
isa指針
superclass指針
類的屬性資訊(@property)、類的對象方法資訊(instance method)
類的協定資訊(protocol)、類的成員變量資訊(ivar)
…
記憶體存儲圖示
-
元類對象
執行以下代碼擷取元類對象
// object_getClass 函數:傳入執行個體對象傳回類對象,傳入類對象,傳回元類對象
Class objectClass3 = object_getClass([NSObject class]);
總結:
objectMetaClass是NSObject的meta-class對象(元類對象)
每個類在記憶體中有且隻有一個meta-class對象
meta-class對象和class對象的記憶體結構是一樣的,但是用途不一樣,在記憶體中存儲的資訊主要包括
isa指針
superclass指針
類的類方法資訊(class method)
…
關于如何證明剛剛所總結的三種類型的對象分别存儲的什麼資訊,通過閱讀蘋果源碼可知
- 簡單圖示 想要更深層次的了解類的本質還是需要自己去閱讀源碼
iOS OC對象的本質窺探(對象分類)(二)
分析:執行個體對象,類對象和元類對象中都有isa指針,而類對象和元類對象中除了含有isa指針之外還有superclass指針,問題:isa指針和superclass指針分别有什麼作用呢?
- 分析 建立一個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
// 調用
Person *person = [[Person alloc] init];
[person personInstanceMethod];
[Person personClassMethod];
- isa指針作用
OC語言是消息機制 當執行[person personInstanceMethod]; 這行代碼時 實際會被編譯成 objc_msgSend(person, @selector(personInstanceMethod))進行調用,那麼剛剛說到執行個體對象中不存儲方法,那麼當調用時這個對象方法是怎麼獲得的呢?
圖示:答案: 當執行個體對象調用對象方法時是通過isa指針,指向自己的類對象,找到類對象中的方法資訊,進行調用。同理,當執行 [Person personClassMethod]; 這行代碼時,執行個體對象通過isa指針指向自己的類對象,又通過類對象中的isa指針指向元類對象,擷取到類方法資訊。
iOS OC對象的本質窺探(對象分類)(二) - 建立一個Person類給person類分别聲明一個對象方法和一個類方法,再建立一個繼承于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
// 調用
Student *student = [[Student alloc] init];
[student personInstanceMethod];
[Student personClassMethod];
- superclass指針作用
總結:當執行[student personInstanceMethod]這行代碼時 student對象通過isa指針找到自己類對象,結果發現類對象中沒有personInstanceMethod這個方法,然後利用superclass指針找到父類也就是Person的類對象,檢視是否有 personInstanceMethod 方法資訊,如果有 就調用,沒有的話繼續向上查找。同理:當執行[Student personClassMethod]; 這行代碼時,student對象通過isa指針找到自己類對象,又通過類對象的isa指針找到自己的元類對象結果發現元類對象中沒有personClassMethod這個方法,元類對象利用superclass指針向上逐級尋找父類的元類對象是否有此方法。直到NSobject停止,如果找到就調用,找不到就會奔潰 unrecognized selector sent to class 0x1000011a0'
圖示:
最後總結:
#####instance -> 執行個體對象,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調用對象方法的軌迹
9.isa找到class,方法不存在,就通過superclass找父類
10.class調用類方法的軌迹
11.isa找meta-class,方法不存在,就通過superclass找父類
圖示:
- 畫一下[student personInstanceMethod]這行代碼的執行順序
iOS OC對象的本質窺探(對象分類)(二) - 畫一下[Student load]這行代碼的執行順序
iOS OC對象的本質窺探(對象分類)(二)
疑問???類方法再調用時先去自己的元類對象中尋找,如果沒有就去父類的元類對象中尋找,在沒有就去NSObject的元類對象中尋找,再就去NSObject的類對象中尋找(根據最上面的線可以看來)那是這麼回事嗎?下面來驗證一下
//建立一個Car類,繼承自NSObject
@interface Car : NSObject
@end
@implementation Car
@end
// 建立一個NSObject的類别
//.h中代碼
+ (void)test;
//.m中代碼
+ (void)test{
NSLog(@"+[NSObject test] - %p", self);
}
//調用代碼
[Car test];
輸出 :[Car class] - 0x100001220
别的代碼都不變,将類别中.m中的代碼改成
//+号變成-号
- (void)test{
NSLog(@"+[NSObject test] - %p", self);
}
輸出 :[Car class] - 0x100001220
再調用發現還是可以成功,具體的原因吧,我也說的不是很好,就不誤導别人了,如果有大神知曉,歡迎指正
如有疑問歡迎指正~
強烈推薦:
iOS擷取手機唯一标示
iOS 高德地圖實作大頭針展示,分級大頭針,自定制大頭針,在地圖上畫線,線和點共存,路線規劃(駕車路線規劃),路線導航,等一些常見的使用場景
如有疑問請看:iOS OC對象的本質窺探(一)