美文网首页iOS底层原理整理
Category原理解析(2)-关联对象

Category原理解析(2)-关联对象

作者: 周灬 | 来源:发表于2019-07-17 16:09 被阅读0次

1.分类为什么不能添加属性(成员变量)?

①.分类是用于给原有类添加方法的,因为分类的结构体指针中,没有成员变量列表(结构请看上一篇文章--Category原理解析(1))。所以原则上讲它只能添加方法, 不能添加成员变量,实际上可以通过其它方式添加成员变量 ;
②.分类中的可以写@property, 但只会生成对应setget方法的声明,不会去实现setter/getter方法以及私有的成员变量(编译时会报警告);
③.可以在分类中访问原有类中.h中的属性;

问题
1.为什么在分类中声明属性时,运行不会出错呢?
      我们知道在一个类中用@property声明属性,编译器会自动帮我们生成成员变量和setter/getter,但分类的指针结构体中,根本没有成员变量列表。所以在分类中用@property声明属性,既无法生成成员变量也无法生成setter/getter的实现。
2.既然分类不让添加属性,那为什么我们写了@property仍然还以编译通过呢?
      我们可以用@property声明属性,编译和运行都会通过,只要不使用程序也不会崩溃。但如果调用了_成员变量和setter/getter方法,报错就在所难免了。

2. 关联对象给分类添加属性

//Student.h
@interface Student : NSObject
/** class */
@property(nonatomic, copy)NSString *className;
@end
//Student+Extern.h(分类)
@interface Student (Extern)
/** name */
@property(nonatomic, copy)NSString *name;
@end
//Student+Extern.m
#import "Student+Extern.h"
#import <objc/runtime.h>
static NSString *nameKey = @"nameKey";   //定义一个key值
@implementation Student (Extern)
- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
    return objc_getAssociatedObject(self, &nameKey);
}
@end

一. 关联对象给分类添加属性的基本用法

添加关联对象:

void objc_setAssociatedObject(id object, const void * key,
                                id value, objc_AssociationPolicy policy)

获取关联对象:

objc_getAssociatedObject(id object, const void * key)

移除所有的关联对象:

void objc_removeAssociatedObjects(id object)

key的常见的用法:

//key是myKey的自己的地址值
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
//key是字符串
static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
//使用属性名作为key(@"property"在常量区,所以@"property"的地址是相同的)
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))
//使用get方法的@selecor作为key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
//隐式参数
//get方法中的_cmd = @selector(name)
objc_getAssociatedObject(self,_cmd)

二. 关联对象的原理

实现关联对象技术的核心对象有:
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation

objc4源码解读:objc-references.mm


关联对象的数据结构.png 关联对象的存取结构.png
void objc_setAssociatedObject(id object, const void * key,
                              id value,
       objc_AssociationPolicy policy)

原理说明
1.AssociationHashMap中的disguised_ptr_t是参数中object,AssociationsHashMap是一个全局的map.
2.AssociationsMap的void*是参数中key.
3.objectAssociation的policy就是参数中的policy,value就是参数中的vlaue.

关联数据注意:
关联对象并不是存储在被关联对象本身内存中
关联对象存储在全局的统一的一个AssociationsManager中
设置关联对象为nil,就相当于是移除关联对象

                            想了解更多iOS学习知识请联系:QQ(814299221)

相关文章

网友评论

    本文标题:Category原理解析(2)-关联对象

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