在没有介绍关联对象之前,先看一道面试题
Category能否添加成员变量?如果可以,如何给Category添加成员变量?
在Cateogry底层学习笔记中,注意
的第一条category里面不能添加成员变量。但是可以通过关联对象间接的实现成员变量效果
。
在Category中,给分类添加属性方法,只会给分类添加属性的set方法和get方法的声明。不会像在类中,给类添加属性,同时生成成员变量,set方法的声明和实现以及get方法的声明和实现。我们来看下Category的底层结构图:
![](https://img.haomeiwen.com/i1518543/b9847faa78580135.png)
在Category的底层结构中,包括实例方法列表
method_list_t
、类方法列表method_list_t
、协议列表protocol_list_t
、属性列表property_list_t
。但是没有成员变量列表ivars
。所以要实现成员变量功能,可以通过其他方式,关联对象就是其中的一种方式。
我们先看下,关联对象的使用方式
main.m的调用方式
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+Test3.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
person.name = @"糖糖";
NSLog(@"%d %d %@",person.weight,person.height,person.name);
}
return 0;
}
类文件
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
#import "Person.h"
@implementation Person
@end
在分类中使用关联对象
#import "Person.h"
@interface Person (Test3)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test3.h"
#import <objc/runtime.h>
@implementation Person (Test3)
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self,@selector(name),name,OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self,_cmd);
}
@end
关联对象的原理
实现关联对象技术的核心对象有
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
AssociationsManager内部有static AssociationsHashMap *_map;
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
_object_set_associative_reference(object, (void *)key, value, policy);
}
在AssociationsHashMap
的内部,包含ObjectAssociationMap
。
class AssociationsHashMap : public unordered_map<disguised_ptr_t,
ObjectAssociationMap *, DisguisedPointerHash,
DisguisedPointerEqual, AssociationsHashMapAllocator> {
...
};
在ObjectAssociationMap
内部包含ObjcAssociation
。
class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {
...
};
在ObjcAssociation
内部,有两个重要属性_policy
,_value
;
class ObjcAssociation {
uintptr_t _policy;
id _value;
...
};
在objc_setAssociatedObject(object, const void *key, id value, objc_AssociationPolicy policy)
方法中,传入的参数value
,policy
,最后传入ObjcAssociation
内部。
![](https://img.haomeiwen.com/i1518543/b1c9c0189216fd07.png)
-
AssociationsManager
内部的AssociationsHashMap
有成对的keydisguised_ptr_t
和valueObjectAssociationMap
值。 - 在
ObjectAssociationMap
内部也有成对的key值void *
和value值ObjectAssociation
- 在
ObjectAssociation
内部有value
,policy
。
在objc_setAssociatedObject(object, const void *key, id value, objc_AssociationPolicy policy)
方法内, - object是key值
disguised_ptr_t
; - const void *key是key值
void *
; - id value 是
ObjectAssociation
内部的value
,bjc_AssociationPolicy policy是
ObjectAssociation内部的
policy`。
网友评论