如何给Category增加属性
2020/7/13 23:09:15
本文主要是介绍如何给Category增加属性,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
本文已经添加到专辑:《彻底弄懂OC》。 欢迎加入我的QQ群:661461410
,一起探讨iOS底层原理。
相关问题
- 分类可以添加属性吗? 如果可以,应该如何实现。
背景知识
我们知道在一个类中增加一个属性,编译器会帮我们做3件事,比如,我们给Person
这个类增加一个属性age
,编译之后,类中会增加一个成员变量_age
, 增加get方法和set方法的生命与实现 -(int)age
和 -(void)setAge:(int)age
。
但是我们在分类里面声明一个属性,会帮我们声明两个方法set, get。 但不会生成实现,也不会产生成员变量。所以我们不能直接给Category添加成员变量,但是可以间接实现Category有成员变量的效果。
实现分类添加属性
使用全局变量
下面代码中,我们为person的分类增加了一个age属性,我们通过声明一个全局变量_age,将age的值存储到_age中。
@interface Person (Test) @property (nonatomic, assign) int age; @end @implementation Person (Test) int _age; - (void)setAge:(int)age { _age = age; } -(int)age { return _age; } @end 复制代码
但,这种方式有致命的确定,就是多个实例对象共用_age,导致数据错误。
使用字典
#import "Person+Test.h" @implementation Person (Test) NSMutableDictionary *_ageDic; + (void)load { _ageDic = [[NSMutableDictionary alloc] init]; } - (int)age { NSString *selfKey = [NSString stringWithFormat:@"%p", self]; return [[_ageDic valueForKey: selfKey] intValue]; } - (void)setAge:(int)age { NSString *selfKey = [NSString stringWithFormat:@"%p", self]; [_ageDic setValue:@(age) forKey:selfKey]; } @end 复制代码
使用字典来存储值解决上一种方法中多个对象导致数据错乱的问题,但它也有一些问题,如下:
- 多线程问题。
- 每增加一个属性都要新增一个字段,拓展性太差,假如再加一个属性name,就需要增加一个字段用来存储对象对应的name值。
- 属性是存储在字段内部的,并不是存储在类的对象内部。
关联对象
#import "Person+Test.h" #import <objc/runtime.h> @implementation Person (Test) - (int)age { return [objc_getAssociatedObject(self, @selector(age)) intValue]; } - (void)setAge:(int)age { objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_ASSIGN); } @end 复制代码
这种方式,我们使用runtime提供的两个方法objc_setAssociatedObject
和 objc_setAssociatedObject
来分别设置和获取属性值。就objc_setAssociatedObject
而言其接受三个参数:
-
id,表示为当前对象关联属性。
-
key,关联属性对应的唯一key,这里我们使用get方法的函数地址值。
-
value,key对应的值。
-
objc_AssociationPolicy, 存储策略。有5个取值,根据属性的类型选择对应的内存存储策略。
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
关联对象实现原理
关联对象的底层实现涉及到了4个类,分别是:
- AssociationsManager
- AssociationsHashMap
- ObjectAssociationMap
- ObjcAssociation
其实现结构如下:
其中 AssociationsHashMap
中 disguised_ptr_t
表示对象,AssociationMap
中的 void *
表示 key
。ObjectAssociation
中包含value
和存储策略。
我们以上面的Person对象为例,图示一下整体的结构。
总结
通过上面的分析,我们回答一下开头的问题:
分类不可以直接添加属性,但可以间接添加,最优雅的方式是通过关联对象进行属性与分类的绑定。
那么,留一个问题,你认为关联对象需要手动释放吗? 在类销毁的时候,需要释放其通过关联对象绑定的属性吗?
互动交流
这篇关于如何给Category增加属性的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值