OC 类属性探究

这个问题的起源于我们知道类方法是存在元类对象中,那么类属性是否也存在元类对象中?这个问题咋一看可能就会回答说:“存在的”。但是有个哥们就提出 OC 中有类属性吗?所以才有了这篇文章的探究。

一、什么是类属性

首先类属性是存在的。在 2016 的 WWDC 上指出,从 Xcode8开始,LLVM 已经支持 OC 显示的声明类属性,以便和 Swift 的类属性进行交互操作。其中 OC 中的类属性通过 class 关键字显示声明,如下图示:

二、类属性是否存在元类对象中

上面我们已经知道了什么是类属性,接着我们来看一下类属性是否存在元类对象中。可以通过如下代码打印一下元类对象中的属性列表。

/** 1、获取元类对象 */
Class metaClass = object_getClass([Person class]);
/** 2、获取元类属性列表 */
unsigned int count = 0;
objc_property_t *propertList = class_copyPropertyList(metaClass, &count);
for (int i = 0; i < count; i++) {
    NSLog(@"%s",property_getName(propertList[i]));
}

其中 Person 类中只声明了一个类属性

@interface Person : NSObject

@property (class) NSString *name;

@end

对应控制台打印结果如我们预想的一样打印出来了 name 属性,验证成功。

三、类属性如何使用

一开始在接触这个类属性时,很简单的认为可以直接通过点语法进行使用,结果 too young,too simple;直接就崩溃掉了,也就意味着类属性没有 set 方法。于是笔者又接着去打印了一下 Method List,空空如也。黑人问号脸?紧接着就在 WWDC 中找到了类属性的使用介绍,使用 class 声明的属性是不会自动合成 ivar 以及 set/get 方法,需要手动合成。隐隐感到类属性的鸡肋。

四、使用动态方法解析来处理类属性

上述介绍了可以手动合成 ivar 和 set/get 方法。接着我们来通过动态方法解析来进行处理。

在Person.m文件中添加一下代码

+ (BOOL)resolveClassMethod:(SEL)sel{
    NSString *methodName = NSStringFromSelector(sel);
    if ([methodName isEqualToString:@"setName:"]) {
        return class_addMethod(object_getClass([Person class]), sel, (IMP)customSetName, "v@:@");
    }
    if ([methodName isEqualToString:@"name"]) {
        return class_addMethod(object_getClass([Person class]), sel, (IMP)customGetName, "@@:");
    }
    return NO;
}

void customSetName(id self, SEL _cmd, NSString *param){
    objc_setAssociatedObject(self, LGCLASSIVARKEY, param, OBJC_ASSOCIATION_COPY);
}

id customGetName(id self, SEL _cmd){
    return objc_getAssociatedObject(self, LGCLASSIVARKEY);
}

测试访问类属性

Person.name = @"hello";
NSLog(@"person name value --- %@",Person.name);

经过上述处理如我们所愿能够正常访问 name 属性

总结

以上就是我们关于类属性的探究。现对本文知识点进行一下总结

  • OC 中类属性通过 class 关键字进行声明,且类属性存在元类对象中

  • 类属性不会自动合成 ivar 以及 set/get 方法,需要手动合成

ps : 本文中部分图片引用来自 WWDC2016

你可能感兴趣的:(OC 类属性探究)