根據上一篇博客iOS-class、object_getClass、objc_getClass、objc_getMetaClass區別的研究發現,發現主要還是class方法和objc_getClass方法的區別,因此本篇文章主要講述一下class方法和objc_getClass方法,
一、Object(objc實體物件),Class(類),Metaclass(元類),Rootclass(根類),Rootclass‘s metaclass(根元類)
首先說下Objective-C中類的幾種資料結構;在Objective-C的型別結構中,Object(實體),Class(類),Metaclass(元類),Rootclass(根類),Rootclass‘s metaclass(根元類),且這些都是物件,
我們可用過兩張圖了解一下上述型別中的關系圖
1、經典的Objective-C的物件模型圖

2、 實體物件(Object),類(CLass),元類(Metaclass)之間的關系

實體物件(Object): 我們創建的一個物件或實體objc其實就是一個struct objc_object結構體,這個結構體只有一個成員變數,這是一個Class型別的變數isa,也是一個結構體指標,這個objc物件的isa指標指向他的類物件(即平時我們所說的類)
類(CLass):存盤Object實體的相關資料,如:實體方法串列、成員變數串列、屬性串列,
元類(Metaclass):存盤Class相關的資料,如:類方法串列、類的資訊等,
參考蘋果官方公開原始碼
objc4原始碼在線瀏覽
objc4原始碼下載
二、class方法和objc_getClass方法
1、class方法
實體方法 - (CLass)class;
類方法 + (Classs)class
在蘋果公開的官方objc原始碼,NSObject.mm檔案中:
// 類方法,回傳自身
+ (Class)class {
return self;
}
// 實體方法,查找isa(類)
- (Class)class {
return object_getClass(self);
}
2、object_getClass方法
object_getClass(id _Nullable obj)
(1)傳入引數:obj可能是instance物件、class物件、meta-class物件
(2)回傳值:
【1】如果是instance物件,回傳class物件
【2】如果是class物件,回傳meta-class物件
【3】如果是meta-class物件,回傳NSObject(基類)的meta-class物件
官方原始碼:
/***********************************************************************
* object_getClass.
* Locking: None. If you add locking, tell gdb (rdar://7516456).
**********************************************************************/
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
三、objc物件型別
我們首先通過objc_getClass方法獲取isa指標,即指向類物件的指標
objc_getMetaClass方法獲取類物件中的isa指標,即指向元類物件的指標
代碼如下:
Class c1 = objc_getClass("People");
Class c2 = objc_getMetaClass("People");
NSLog(@"objc_getClass---- %p",c1);
NSLog(@"objc_getMetaClass---- %p",c2);
輸出結果:

1、obj為實體物件
在Object-C中,Object本質上是一個struct,在這個struct中會保存一個名為isa的指標,該指標會指向該Object的類,定義如下所示:
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
我們初始化一個類的實體可以直接用id來定義,那么id就是上面這樣定義的,所以類的實體初始化完了之后,它的內部就多了一個isa指標,這個指標型別指向的是struct objc_class的結構體,其實也就是指向了這個實體所屬的類,
代碼如下:
//obj為實體物件
id obj = [[People alloc]init];
People *people = obj;
/*----obj為實體物件----*/
Class cls = [obj class];
Class cls2 = object_getClass(obj);
Class cls3 = [people class];
Class cls4 = object_getClass(people);
NSLog(@"");
NSLog(@"----obj為實體物件----");
NSLog(@"實體物件:class---- %p" , cls);
NSLog(@"實體物件:object_getClass---- %p" , cls2);
NSLog(@"實體物件:class---- %p" , cls3);
NSLog(@"實體物件:object_getClass---- %p" , cls4);
輸出結果:

當obj為實體變數時
object_getClass(obj)與[obj class]輸出結果一直,均獲得isa指標,即指向類物件的指標,
2、obj為Class類物件
在Objective-C中,任何類的定義都是物件(除了int、char等這些基本型別),類和類的實體(物件)沒有任何本質上的區別,任何物件都有isa指標,
我們打開Xcode中 <obc/runtime.h> 頭檔案或者蘋果公開的objc官方原始碼runtime.h檔案中,里面有一個結構體定義
struct object_class{
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類
const char *name OBJC2_UNAVAILABLE; // 類名
long version OBJC2_UNAVAILABLE; // 類的版本資訊,默認為0
long info OBJC2_UNAVAILABLE; // 類資訊,供運行期使用的一些位標識
long instance_size OBJC2_UNAVAILABLE; // 該類的實體變數大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變數鏈表
struct objc_method_list *methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法快取
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協議鏈表
#endif
}OBJC2_UNAVAILABLE;
這個結構體其實就是我們所說的 類 ,他的 Class isa這個指標的型別點進去會發現,定義如下:
// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
原來isa指標指向的依然是個 objc_class 結構體,只不過為了語意化起個名字叫Class
代碼如下:
//obj為實體物件
id obj = [[People alloc]init];
People *people = obj;
//classObj為類物件
Class classObj = [obj class];
/*----obj為類物件----*/
Class clsc = [classObj class];
Class clsc2 = object_getClass(classObj);
NSLog(@"");
NSLog(@"----obj為類物件----");
NSLog(@"類物件:class---- %p" , clsc);
NSLog(@"類物件:object_getClass---- %p" , clsc2);
輸出結果:

當obj為類物件時
object_getClass(obj)回傳類物件中的isa指標,即指向元類物件的指標;
[obj class]回傳的則是類物件其本身
3、obj為Metaclass類(元類)物件
Metaclass元類與Class的結構是一樣的,只是職能不同,
類(CLass):存盤Object實體的相關資料,如:實體方法串列、成員變數串列、屬性串列,
元類(Metaclass):存盤Class相關的資料,如:類方法串列、類的資訊等,我們可以參考頭部實體物件(Object),類(CLass),元類(Metaclass)之間的關系圖解
代碼如下:
//obj為實體物件
id obj = [[People alloc]init];
//classObj為類物件
Class classObj = [obj class];
//metaClassObj為元類物件
Class metaClassObj = object_getClass(classObj);
/*----obj為元類物件----*/
Class clso = [metaClassObj class];
Class clso2 = object_getClass(metaClassObj);
NSLog(@"");
NSLog(@"----obj為元類物件----");
NSLog(@"元類物件:class---- %p" , clso);
NSLog(@"元類物件:object_getClass---- %p" , clso2);
輸出結果:

當obj為Metaclass(元類)物件時
object_getClass(obj)回傳元類物件中的isa指標,因為元類物件的isa指標指向根類,所有回傳的是根類物件的地址指標;
[obj class]回傳的則是元類本身
4、obj為Rootclass類(根類)物件
Rootclass就是根類,任何類的Metaclass中的isa指標都是指向根類,且結構與Class結構是一樣的,
代碼如下:
//obj為實體物件
id obj = [[People alloc]init];
//classObj為類物件
Class classObj = [obj class];
//metaClassObj為元類物件
Class metaClassObj = object_getClass(classObj);
//rootClassObj為根類物件
Class rootClassObj = object_getClass(metaClassObj);
/*----obj為根類物件----*/
Class clsr = [rootClassObj class];
Class clsr2 = object_getClass(rootClassObj);
NSLog(@"");
NSLog(@"----obj為根類物件----");
NSLog(@"根類物件:class---- %p" , clsr);
NSLog(@"根類物件:object_getClass---- %p" , clsr2);
輸出結果:

當obj為Rootclass(根類)物件時
object_getClass(obj)回傳根類物件中的isa指標,因為根類物件的isa指標指向Rootclass‘s metaclass(根元類),即回傳的是根元類的地址指標;
[obj class]回傳的則是其本身,
因為根類的isa指標其實是指向本身的,所有根元類其實就是根類,所有輸出的結果是一樣的,
四、結論
1、object_getClass(obj)
回傳的是obj的isa指標
2、[obj class]
(1)obj為實體物件
呼叫的是實體方法:- (Class)class,回傳的obj物件中的isa指標;
(2)obj為類物件(包括元類和根類以及根元類)
呼叫的是類方法:+ (Class)class,回傳的結果為呼叫者本身,
這時候我們再回過頭看看Object-C的物件模型圖,思考一下會發現
1、記憶體創建一個instance實體物件(People *people),同時會創建一個與之對應的類物件(Class peopleClass)和元類物件(Class peopleMeta);
注:實體物件通過calloc可創建多個,但類物件和元類物件在記憶體中只有一份,只創建一次;
2、物件的本質,其實是C語言的結構體struct,各個物件的記憶體結構為:
people:isa指標+僅存盤Person類成員變數的值;
People:isa指標+superclass指標+存盤成員變數的型別、名稱,協議,物件方法等;
peopleMeta:isa指標+superclass指標+僅存盤類方法;
3、isa指向:
people:指向類物件People;
People:指向元類物件peopleMeta;
peopleMeta:指向基類(Root,如:NSObject)的元類物件meta(基類的元類物件的isa指向該元類物件自己);
4、superclass指向:
People:指向父類>>基類的類物件指向nil;
peopleMeta:指向父類>>基類的元類物件指向該基類的類物件;
GitHub示例代碼Demo
參考文章:
iOS筆記--class方法和objc_getClass方法
object_getClass(obj)與[obj class]的區別
class和object_getClass方法區別
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/306265.html
標籤:其他
上一篇:哈羅出行自動化測驗搶單測驗程式
下一篇:iOS-class、object_getClass、objc_getClass、objc_getMetaClass區別
