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