iOS 底层 day07 Category上的关联对象

一、本文解答的问题

1. 为什么中添加属性可以赋值取值,而分类中添加的属性却不能直接赋值取值呢?
  • 假设添加属性的代码是 @property(nonatomic, assign) int age;
  • 中添加属性等价于做了三件事:①添加成员变量_age ②声明 agesetAge: 方法 ③添加 agesetAge:的方法实现
  • 分类 中添加属性等价于只做了一件事:声明 agesetAge: 方法,没有成员变量,也没有方法实现
  • 所以我们在分类中使用分类的属性,将会得到如下错误'-[Person setAge:]: unrecognized selector sent to instance'
2. 不使用Objective-C提供的objc_setAssociatedObject 相关 API 我们能自己实现关联对象的效果吗?如果有,有哪些思路?
  • 可以
  • 有问题3,4两种思路
3. 观察下面代码,实现了关联对象效果,能否正常使用?有哪些缺点?可以优化吗?
// Person+Test1.h 
#import "Person.h"
@interface Person (Test1)
@property(nonatomic, assign) int age;
@end

// Person+Test1.m
#import "Person+Test1.h"
static int age_;

@implementation Person (Test1)
- (void)setAge:(int)age {
    age_ = age;
}
- (int)age {
    return age_;
}
@end
  • 能使用,但是有几个缺点
  • ①所有的Person的实例变量,都是使用同一个关联对象,设置和取值都会相互被影响
  • ②存在线程安全问题
  • ③写法比较麻烦,分类每次增加属性,都需要额外增加静态变量来存值
  • ④类销毁,age_未释放,所以存在内存泄露问题
  • 优化如下,看问题4
4. 我们对上面的代码优化一下,观察下面代码,实现了关联对象效果,能否正常使用?有哪些缺点?可以优化吗?
#import "Person+Test1.h"
#define SPKey [NSString stringWithFormat:@"%p",self]
static NSMutableDictionary *ageDic;
@implementation Person (Test1)
+ (void)load {
    ageDic = [[NSMutableDictionary alloc] init];
    
}
- (void)setAge:(int)age {
    [ageDic setObject:@(age) forKey:SPKey];
}
- (int)age {
    return [[ageDic valueForKey:SPKey] intValue];
}
@end
  • 上述代码更加完善了,Person的实例对象之间不会相互影响,能够达到关联对象的效果
  • 依然还有的缺点是:
  • ①写法比较繁琐
  • ②存在线程安全问题
  • ③类销毁,ageDic未释放,所以存在内存泄露问题
5. 用Objective-C提供的objc_setAssociatedObject 相关 API ,实现关联对象怎么做?
#import "Person+Test1.h"
#import 
@implementation Person (Test1)
- (void)setAge:(int)age {
    objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_ASSIGN);
}
- (int)age {
    return [objc_getAssociatedObject(self, @selector(age)) intValue];
}
@end
  • 代码简洁
  • 如果类销毁,关联对象也会被擦除
  • 有内存管理策略 policy ,线程相对安全些
6. 关联对象的实现原理图解
关联对象的实现原理图解

二、关联对象源码解读

1. 掌握四个核心类
  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation
2. 核心源码
class AssociationsManager {
    static AssociationsHashMap *_map;
}

class AssociationsHashMap : public unordered_map

class ObjectAssociationMap : public std::map

class ObjcAssociation {
        uintptr_t _policy;
        id _value;
}

你可能感兴趣的:(iOS 底层 day07 Category上的关联对象)