学习笔记:底层原理day07

141 阅读2分钟

在category中声明@property,只会生成方法的生命。不会生成成员变量,也不会生成方法的现实现

如果在category里面时间写成员变量{

int _age;

会报错,说不能在category中声明成员变量。

但是可以间接添加。

怎么间接添加呢?

首先:Person(Test)的.h文件中还是要写上@property (nonatomic,assign)int age;

怪招1:

@implement Person(Test)

Int age_;

-(void)setAge:(int)age {

age_ = age;

}

-(int)age {

return age_

}

怪招1会导致所有的Person类的age值都是一样的。

怪招2:

@implement Person(Test)

+ (void)load {

ages_ = [NSMultableDictionary dictionary];

}

NSMultableDictionary *ages_;

-(void)setAge:(int)age {

NSString *key = [NSString stringWithFormat:@“%p”,self];

ages_[key] = @(age);

}

-(int)age {

NSString *key = [NSString stringWithFormat:@“%p”,self];

return [ages_[key].intValue];

}

怪招2,如果多个对象在不同线程同时访问,有可能有线程问题。

正规做法:关联对象。

#Import <objc/runtime>

objc_AssociationPolicy(绑定策略)的所有值的解析:

OBJC_ASSOCIATION_ASSIGN assign

OBJC_ASSOCIATION_RETAIN_NONATOMIC strong,nonatomic

OBJC_ASSOCIATION_COPY_NONATOMIC copy,nonatomic

OBJC_ASSOCIATION_RETAIN strong,atomic

OBJC_ASSOCIATION_COPY copy,atomic

使用:.h还是有一个@property (nonatomic, assign) age;

// 这样定义key是有漏洞的,别人可以通过extern const void *AgeKey;然后访问和修改(可以加上static const void*)。并且这样定义比较麻烦

const void *AgeKey = &AgeKey; // AgeKey这个const void对象,存的是自己的地址值,如0x39877834

@implement Person(Test)

// object:给谁绑定,key:绑定的key,value,绑定什么值,policy:绑定策略

// objc_setAssociatedObject(id _Nonnull object, const void *_Nonnull key, id _Nonnull value, objc_AssociatioinPolicy policy)

-(void)setAge:(int)age {

objc_setAssociatedObject(self, AgeKey, @(age), OBJC_ASSOCIATION_ASSIGN)

}

-(int)age {

return objc_getAssociatedObject(self, AgeKey).intValue;

}

======================================================================

static const char AgeKey;

-(void)setAge:(int)age {

objc_setAssociatedObject(self, &AgeKey, age, OBJC_ASSOCIATION_ASSIGN)

}

========================================================

如果在两个不同地方,写两个@“name”,其实是同一个来的,因为他们都放在常量区。

#define AGE_KEY @“age”

-(void)setAge:(int)age {

objc_setAssociatedObject(self, AGE_KEY, age, OBJC_ASSOCIATION_ASSIGN);

}

========================================================

@selector(age)不管写多少次,都是同一个,都是指向某个地址值

-(void)setAge:(int)age {

objc_setAssociatedObject(self, @selector(age), age, OBJC_ASSOCIATION_ASSIGN);

}

// _cmd相当于@selector(age) 当然,要保持跟setAge:方法中的一样,所以只能在age方法中写

-(int)age {

objc_getAssociatedObject(self, _cmd);

}

这种通过关联对象添加的属性,不会改变Person类这个结构体的结构,而且也不是存在Person类对象,也不是存储在Person实例对象里面的。

原理分析::

关联对象并不是存储在被关联对象本身的内存中

关联对象存储在全局的统一的AssociationsManager中

设置管理对象为nil,相当于是移除关联对象。 —》 比如person.age = nil; objc_setAssociatedObject(self, key, nil, policy)

移除关联对象:

Person *person = [Person alloc] init]

objc_removeAssociatedObjects(id object)

objc_removeAssociatedObjects(person);