iOS-classobject_getClassobjc_getClassobjc_getMetaClass区别

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS-classobject_getClassobjc_getClassobjc_getMetaClass区别相关的知识,希望对你有一定的参考价值。

在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区别

以上是关于iOS-classobject_getClassobjc_getClassobjc_getMetaClass区别的主要内容,如果未能解决你的问题,请参考以下文章