iOS-底层原理(7)-关联对象

面试题
1. Category能否添加成员变量?如果可以,如何给Category添加成员变量?
  • 不能直接给Category添加成员变量,但是可以间接实现Category有成员变量的效果
序言
  • 给一个分类添加成员变量,实际上在类的实现方法中会添加一个带下划线的成员变量和set,get方法。

代码例子如下

@interface Person : NSObject
/** age*/
@property(nonatomic,assign)int age;
@end

@implementation Person {
    int _age;
}
- (void)setAge:(int)age {
    NSLog(@"setAge %d",age);
    _age = age;
}
- (int)age {
    NSLog(@"getAge %d",_age);
    return _age;
}
@end

// 调用
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
        person.age = 100;
        NSLog(@"age = %d",person.age);
    }
    return 0;
}

打印结果

image.png
思考:如何实现给分类“添加成员变量”?
  • 默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现。

  • 关联对象提供了以下API

  • 添加关联对象

void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
  • 获得关联对象
id objc_getAssociatedObject(id object, const void * key)
  • 移除所有的关联对象
void objc_removeAssociatedObjects(id object)
key的常见用法

公用方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person1 = [[Person alloc] init];
        person1.age = 5;
        person1.name = @"person1";
        person1.weight = 10;
        
        Person *person2 = [[Person alloc] init];
        person2.age = 50;
        person2.name = @"person2";
        person2.weight = 100;
        
        NSLog(@"person1 - age is %d, name is %@, weight is %d", person1.age, person1.name, person1.weight);
        NSLog(@"person2 - age is %d, name is %@, weight is %d", person2.age, person2.name, person2.weight);
    }
    return 0;
}
  • 1.static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, MyKey);

代码如下:

@implementation Person (Test)

static const void *NameKey = &NameKey;
static const void *WeightKey = &WeightKey;

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name {
    return objc_getAssociatedObject(self, NameKey);
}

- (void)setWeight:(int)weight {
    objc_setAssociatedObject(self, WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight {
    return [objc_getAssociatedObject(self, WeightKey) intValue];
}
@end
  • 2.static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)

代码如下

@implementation Person (Test)

static const char NameKey;
static const char WeightKey;

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, &NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name {
    return objc_getAssociatedObject(self, &NameKey);
}

- (void)setWeight:(int)weight {
    objc_setAssociatedObject(self, &WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight {
    return [objc_getAssociatedObject(self, &WeightKey) intValue];
}
@end
  • 3.使用属性名作为key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");

代码如下

@implementation Person (Test)

#define NameKey @"name"
#define WeightKey @"weight"

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name {
    return objc_getAssociatedObject(self, NameKey);
}

- (void)setWeight:(int)weight {
    objc_setAssociatedObject(self, WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight {
    return [objc_getAssociatedObject(self, WeightKey) intValue];
}
@end
  • 4.使用get方法的@selecor作为key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))

代码如下

@implementation Person (Test)

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name {
    // 隐式参数
    // _cmd == @selector(name)
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setWeight:(int)weight {
    objc_setAssociatedObject(self, @selector(weight), @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight {
    // _cmd == @selector(weight)
    return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end

运行结果

image.png
关联对象的原理
实现关联对象技术的核心对象有
  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation
objc4源码解读:objc-references.mm
image.png
image.png

本文参考借鉴MJ的教程视频,非常感谢.


项目连接地址 - iOS-associate-object

你可能感兴趣的:(iOS-底层原理(7)-关联对象)