美文网首页OC 底层原理笔记
7OC使用原理 -7-关联对象

7OC使用原理 -7-关联对象

作者: zysmoon | 来源:发表于2020-01-20 14:41 被阅读0次
    面试题
    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;
    }
    
    

    打印结果

    1653926-295227ff50a2b34e.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
    
    

    运行结果

    1653926-8517a3a11a7200a9.png
    关联对象的原理
    实现关联对象技术的核心对象有
    • AssociationsManager
    • AssociationsHashMap
    • ObjectAssociationMap
    • ObjcAssociation
    objc4源码解读:objc-references.mm
    1653926-8ecf7765b025897c.png 1653926-1d31fcfa8b2ea47a.png

    本文参考:
    路飞_Luck (https://www.jianshu.com/p/07f7b96bb03f)
    以及借鉴MJ的教程视频
    非常感谢.


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

    相关文章

      网友评论

        本文标题:7OC使用原理 -7-关联对象

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