iOS底层学习——Category(三)

分类不能直接添加成员变量

前边两篇文章我们介绍了什么是Category。接下来我们看下如何给category添加成员变量
通过读取分类的源码我们知道

struct category_t {
	const char *name;
	classref_t cls;
	struct method_list_t *instanceMethods; // 对象方法列表
	struct method_list_t *classMethods; // 类方法列表
	struct protocol_list_t *protocols; // 协议列表
	struct property_list_t *instanceProperties; // 属性列表

	method_list_t *methodsForMeta(bool isMeta) {
		if (isMeta) return classMethods
		else return instanceMethods
	}
	property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi)
}

可以为一个类的category添加对象,但是我们需要注意到。添加的属性只是声明,没有为这个类添加成员变量,也没有对这个属性实现Set和Get方法

通过关联对象添加成员变量

有关关联对象Runtime提供了以下Api

// 设置关联对象
void objc_setAssociatedObject(id object, const void * key,
                                id value, objc_AssociationPolicy policy)

// 获取关联对象
id objc_getAssociatedObject(id object, const void * key)

// 移除关联对象
void objc_removeAssociatedObjects(id object)

参数说明:
id object:需要关联的对象
const void * key:需要关联的键 这是一个指针类型
id value:就是需要关联的值与上方的key对应。传递nil以清除现有的关联
objc_AssociationPolicy policy:关联策略
关联策略对应的修饰符
在这里插入图片描述

我们创建一个Person类 和他的分类 Test

@interface DDPerson : NSObject
@end


#import "DDPerson.h"
@implementation DDPerson
@end
#import "DDPerson.h"
@interface DDPerson (Test)
@property (copy, nonatomic) NSString *name;
@property (asign, nonatomic) int weight;
@end


#import "DDPerson+Test.h"
#import <objc/runtime.h>

// 定义Name的key
static const char  name_;

@implementation DDPerson (Test)
- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, &name_, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
    return  objc_getAssociatedObject(self, &name_);
}

- (void)setWeight:(int)weight
{
	// 这里我们把weight的get方法当做key, 因为这个参数类型实际上是一个指针类型,所以任何指针类型的参数都可以当做key来使用
    objc_setAssociatedObject(self, @selector(weight), @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight
{
    //获取关联对象的时候,我们用方法的隐式参数_cmd  
    // _cmd 参数是OC方法默认传入的参数,每个方法都会有这个参数。_cmd == @selector(weight) 这个跟setWeight时传入的key刚好对应起来
    return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end

关联对象的原理

关联对象的核心对象有四个,分别为
AssociationsManagerAssociationsHashMapObjectAssociationMapObjcAssociation
在这里插入图片描述

拓展

关联对象的常用key

static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)

static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)

// 使用属性名作为key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");

// 使用get方法的@selecor作为key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值