关联对象

作者: iLeooooo | 来源:发表于2019-02-16 11:41 被阅读21次

O、题:Category能否添加成员变量?如果可以,如何给Category添加成员变量?

答:不能直接给Category添加成员变量(由分类的结构决定的),但是可以间接实现Category有成员变量的效果。从分类的底层实现category_t结构体也可以看出来,分类是不能直接添加成员变量的,因为category_t结构体中没有地方存放成员变量。
给Category间接添加成员变量方式:使用关联对象。

拓展
A. 如果在里面写一个属性,系统会帮我们自动在类里面添加该属性的成员变量,set,get方法实现。

@property (nonatomic, assign) int age;

等价于:

@interface LQPerson : NSObject
{
    int _age;
}
//@property (nonatomic, assign) int age;
@end

@implementation LQPerson
- (void)setAge:(int)age {
    _age = age;
}
- (int)age {
    return _age;
}
@end

B. 如果在分类里面写一个属性,系统不会帮我们自动在类里面添加该属性的成员变量,set,get方法实现。只会添加set,get方法申明。

@property (nonatomic, assign) int age;

等价于

@interface LQPerson : NSObject
//@property (nonatomic, assign) int age;
- (void)setAge:(int)age;
- (int)age;
@end

问题:想要在分类中的属性跟类中的属性使用效果相同,该怎么办?

答:
A:在m文件中声明一个全局变量,在set方法中保存属性的值,在get方法中返回保存的属性的值(即全局变量的值)。

@implementation LQPerson (Test)
int age_;
- (void)setAge:(int)age {
    age_ = age;
}
- (int)age {
    return age_;
}
@end

该方法存在的问题:这个属性变成全局性的了,如果该类有多个实例对象,就会出现所有的这个类的实例对象的该属性的值都相同。


B:由于A方法中的值不能一一对应,推倒出B方法,在m文件中声明一个全局动态字典,在set方法中,用self作为key,值作为value来保存属性的值。在get方法中返回用self作为key,在全局字典中取出value的值。

@implementation LQPerson (Test)

NSMutableDictionary *weights_;
+ (void)load {
    weights_ = [NSMutableDictionary dictionary];
}
- (void)setWeight:(int)weight {
    NSString *key = [NSString stringWithFormat:@"%p", self];
    weights_[key] = @(weight);
}
- (int)weight {
    NSString *key = [NSString stringWithFormat:@"%p", self];
    return [weights_[key] intValue];
}
@end

---成功---:该方式与类中的属性的区别是:类里面的属性的值是存储在该类的实例对象内部,而分类中间接实现的属性的值存储在全局的字典对象里面。
---问题---:线程安全问题(可以适应锁解决),比较麻烦。


C:使用关联对象

关联对象API:
// 添加关联对象
void objc_setAssociatedObject(id object, const void * key,
                                id value, objc_AssociationPolicy policy)
// 获得关联对象
id objc_getAssociatedObject(id object, const void * key)
// 移除单个属性的关联对象(把该属性的值设置为nil即可)
void objc_setAssociatedObject(id object, const void * key,
                               nil, objc_AssociationPolicy policy)
// 移除所有的关联对象
void objc_removeAssociatedObjects(id object)
关联策略:
关联策略
#import <objc/runtime.h>
@implementation LQPerson (Test)
const void* LQNameKey;  // LQNameKey = NULL
- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, LQName, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
    return objc_getAssociatedObject(self, LQName);
}
const void* LQAgeKey;
- (void)setAge:(int)age {
    // @(age)是NSNumber类型,使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
    objc_setAssociatedObject(self, LQAgeKey, @(age), OBJC_ASSOCIATION_RETAIN_NONATOMIC);  
}
- (int)age {
    return [objc_getAssociatedObject(self, LQNameKey) intValue];
}
@end

存在的问题:LQNameKey、LQAgeKey没有赋值,就相当于NULL,如果有多个属性,关联的值就会出现混乱。后面赋值的属性会把前面的属性值覆盖。
解决方法:

static const void* LQNameKey = &LQNameKey;
static const void* LQAgeKey = &LQAgeKey;
处理关联对象的key
// 方案一:使用指针地址作为key
static const char kNamekey;
static const char kAgeKey;
objc_setAssociatedObject(self, &kNamekey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_getAssociatedObject(self, &kNamekey);
objc_setAssociatedObject(self, &kAgeKey, @(age), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(self, &kAgeKey)

// 方案二:使用属性名作为key,直接放字符串,相当于使用的是该字符串的地址值
pobjc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
pobjc_getAssociatedObject(obj, @"property");

// 方案三:使用get方法的@selecor作为key,在get方法中可以使用_cmd
// _cmd相当于获取当前方法的@selector
pobjc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
pobjc_getAssociatedObject(obj, @selector(getter))
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_getAssociatedObject(self, @selector(name));
objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(self, @selector(age))

相关文章

  • Swift 为分类增加属性objc_getAssociated

    OC 获取关联对象 Swift 获取关联对象——错误的写法 Swift 获取关联对象——正确的写法 设置关联对象 ...

  • iOS runtime关联对象 objc_setAssociat

    关联对象的作用: 关联对象可以给某个对象关联一个或者多个其他对象,这些对象通过健来区分。 创建存储关联对象objc...

  • 关联对象

    关联对象的方式 关联对象源码基本思路 关联对象的结构:AssociationsHashManager // Ass...

  • 关联对象

    关联对象原理 关联对象并不是存储在被关联对象本身内存中,关联对象存储在全局的统一的一个AssociationsMa...

  • iOS 关联对象

    概述 关联对象顾名思义,就是给对象关联对象的意思,一个对象可以关联多个其他对象,这些对象通过key来区分,存储对象...

  • 关联对象

    关联对象会用被关联对象作为key,将关联对象存储到全局的哈希表里。 AssociationHashMap Asso...

  • iOS关联对象技术原理

    iOS关联对象技术原理 iOS关联对象技术原理

  • 关联对象

    分类里面添加成员变量, 分类里面是不能直接添加成员变量的,但是可以通过runtime间接添加成员变量。 为什么...

  • 关联对象

    能否为分类添加 “成员变量” ? 为分类所添加的成员变量添加在哪里? 所有对象的关联内容都在同一个全局容器内关联对...

  • 关联对象

    分类、类扩展、继承的总结讲述了分类,介绍到分类可以添加属性,但是属性的get、set方法需要通过runtime的关...

网友评论

    本文标题:关联对象

    本文链接:https://www.haomeiwen.com/subject/bjhbeqtx.html