在Objective-C的型別結構中,有幾個比較重要的概念:Object(實體),Class(類),Metaclass(元類),Rootclass(根類),Rootclass‘s metaclass(根元類),且這些都是物件,
對于class、object_getClass、objc_getClass這三種方法,全部回傳CLass類物件;objc_getMetaClass方法回傳元類物件,
objc4原始碼在線瀏覽
objc4原始碼下載 (本文使用的objc4-818.2版本)
1、class方法
實體方法 - (CLass)class;
類方法 + (Classs)class
在蘋果公開的官方objc原始碼,NSObject.mm檔案中:
// 類方法,回傳自身
+ (Class)class {
return self;
}
// 實體方法,查找isa(類)
- (Class)class {
return object_getClass(self);
}
class方法無論是類物件還是實體物件都可以呼叫,可以嵌套,回傳永遠是自身的類物件,如:
Person *p = [[Person alloc]init];
Class *pClass == [p class] == [ [p class]class] == [[ [p class]class]class] == [Person class]
2、object_getClass方法
object_getClass(id _Nullable obj) ;用于獲取一個objc物件的isa指標指向的物件(即平時我們所說的類)
(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;
}
/**
* Returns the class of an object.
*
* @param obj The object you want to inspect.
*
* @return The class object of which \e object is an instance,
* or \c Nil if \e object is \c nil.
*/
OBJC_EXPORT Class _Nullable
object_getClass(id _Nullable obj)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
object_getClass 和 class 同樣可以嵌套,但是 object_getClass 得到的是他的 isa 指向的地址,即:
Person *p = [[Person alloc]init];
p->[Person class]->PersonMetaClass->PersonMetaClass(元類的ISA指標是指向自己的)
意思是 p 的 isa 指向 [Person class] ,[Person class] 的 isa 指向 PersonMetaClass
3、objc_getClass方法
objc_getClass(const char * _Nonnull name)
(1)傳入引數:字串類名
(2)回傳值:對應的類物件
/* Obtaining Class Definitions */
/**
* Returns the class definition of a specified class.
*
* @param name The name of the class to look up.
*
* @return The Class object for the named class, or \c nil
* if the class is not registered with the Objective-C runtime.
*
* @note \c objc_getClass is different from \c objc_lookUpClass in that if the class
* is not registered, \c objc_getClass calls the class handler callback and then checks
* a second time to see whether the class is registered. \c objc_lookUpClass does
* not call the class handler callback.
*
* @warning Earlier implementations of this function (prior to OS X v10.0)
* terminate the program if the class does not exist.
*/
OBJC_EXPORT Class _Nullable
objc_getClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
objc_getClass 無法嵌套,因為引數 是 char 型別,效果和 class 相同(因為不能嵌套,所以和class可以認為是相同的)
4、objc_getMetaClass方法
objc_getMetaClass(const char * _Nonnull name)
(1)傳入引數:字串類名
(2)回傳值:對應類的元類物件
/**
* Returns the metaclass definition of a specified class.
*
* @param name The name of the class to look up.
*
* @return The \c Class object for the metaclass of the named class, or \c nil if the class
* is not registered with the Objective-C runtime.
*
* @note If the definition for the named class is not registered, this function calls the class handler
* callback and then checks a second time to see if the class is registered. However, every class
* definition must have a valid metaclass definition, and so the metaclass definition is always returned,
* whether it’s valid or not.
*/
OBJC_EXPORT Class _Nullable
objc_getMetaClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
驗證:通過 class_isMetaClass 方法可以驗證(判斷是否是元類)
/**
判斷是否是元類
*/
+ (void)isMetaClass {
/**class_isMetaClass 方法
通過 class_isMetaClass 方法可以驗證判斷是否是元類
*/
Class c1 = object_getClass(self);
Class c2 = [self getMetaClassWithChildClass:self];
BOOL object_getClass = class_isMetaClass(c1);
BOOL objc_getMetaClass = class_isMetaClass(c2);
NSLog(@"object_getClass是否是元類:%@",object_getClass?@"YES":@"NO");
NSLog(@"objc_getMetaClass是否是元類:%@",objc_getMetaClass?@"YES":@"NO");
}
/**
獲取類的元類
@param childClass 目標類別
@return 回傳元類
*/
+ (Class)getMetaClassWithChildClass:(Class)childClass{
//轉換字串類別
const char * classChar = [NSStringFromClass(childClass) UTF8String];
//需要char的字串 獲取元類
return objc_getMetaClass(classChar);
}
測驗代碼如下:
- (void)testGetClassP {
//實體物件
People *people = [[People alloc]init];
//類物件
Class peopleClass = [people class];
Class c1 = objc_getClass("People");
Class c2 = objc_getMetaClass("People");
//實體物件
Class c3 = [people class];
Class c4 = object_getClass(people);
//類物件
Class c5 = [peopleClass class];
Class c6 = object_getClass(peopleClass);
NSLog(@"objc_getClass---- %p",c1);
NSLog(@"objc_getMetaClass---- %p",c2);
NSLog(@"");
NSLog(@"----實體物件----");
// NSLog(@"實體物件:people---- %p",people);
NSLog(@"實體物件:class---- %p",c3);
NSLog(@"實體物件:object_getClass---- %p",c4);
NSLog(@"");
NSLog(@"----類物件----");
// NSLog(@"類物件:peopleClass---- %p",peopleClass);
NSLog(@"類物件:class---- %p",c5);
NSLog(@"類物件:object_getClass---- %p",c6);
}
輸出結果如下:

p/x:以十六進制輸出

綜上:
1、objc_getMetaClass 獲取元類MetalClass
2、objc_getClass 獲取對應類Class
3、object_getClass 獲取 object 的isa指標物件
4、class分為
實體方法 - (CLass)class;
類方法 + (Classs)class
看到objc4原始碼下載上的官方原始碼:
// 類方法,回傳自身
+ (Class)class {
return self;
}
// 實體方法,查找isa(類)
- (Class)class {
return object_getClass(self);
}
如果objc為實體物件,則 class方法 和 object_getClass方法一樣,獲得它的isa指標指向的類物件(即指向類物件的指標,即對應的類), 類物件不是元類
如果objc為類物件,則 class方法 獲得 呼叫類本身;object_getClass方法 獲取類物件中的isa指標(即指向元類物件的指標,即元類) ,類物件的isa指標指向的物件是元類
因此,這4個方法中主要還是class方法和objc_getClass方法,請移步參考iOS-class方法和objc_getClass方法
GitHub示例代碼Demo
參考文章
objc_getClass、object_getClass、class區別
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/306266.html
標籤:其他
