美文网首页
iOS-Runtime-使用关联对象给Category添加成员变

iOS-Runtime-使用关联对象给Category添加成员变

作者: Simple_Code | 来源:发表于2018-09-07 14:59 被阅读41次

    开发问题:需要在一个类的Category中添加属性;
    实际实践:通过 Category 给一个现有的类添加属性,却不能添加实例变量;
    解决方案:通过runtime建立关联引用;

    image.png

    从上图分类在OC源码中的结构体,可以看出里面不存在成员变量列表。因此,分类里面的属性在外边是无法通过点语法调用或者get方法的获取的,但是我们可以使用关联对象给Category添加成员变量。从而达到一般类里面属性的正常调用。下面提供四种方法:

    首先介绍两个Runtime相关的关联函数:

        /**
         @param object#> 第一个参数为从该object中获取关联对象
         @param key#> 第二个参数为想要获取关联对象的key
         @param value#> 第三个参数为需要和object建立关联引用对象的value
         @param policy#> 第四个参数为关联策略,等同于给property添加关键字,具体说明如下图关联策略对应图
         */
    objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                             id _Nullable value, objc_AssociationPolicy policy)
    
        /**
         @param object#> 第一个参数为从该object中获取关联对象
         @param key#> 第二个参数为想要获取关联对象的key
         */
    objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
        OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
    
    关联策略对应图.png

    方法1:推荐使用

    #import "Person.h"
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *name;
    @end
    
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY);
    }
    - (NSString *)name {
        return objc_getAssociatedObject(self, @selector(name));
    }
    

    或者

    #import "Person.h"
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *name;
    @end
    
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY);
    }
    - (NSString *)name {
        return objc_getAssociatedObject(self, _cmd);
    }
    

    注:

    _cmd = @selector(name) 隐式参数

    方法2:

    #import "Person.h"
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *name;
    @end
    
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    
    #define SPNameKey @"name"
     - (void)setName:(NSString *)name {
     objc_setAssociatedObject(self, SPNameKey, name, OBJC_ASSOCIATION_COPY);
     }
     - (NSString *)name {
     return objc_getAssociatedObject(self, SPNameKey);
     }
    

    注:

    SPNameKey必须和该Value名称一致

    方法3:

    #import "Person.h"
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *name;
    @end
    
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    
    static const char SPNameKey;
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, &SPNameKey, name, OBJC_ASSOCIATION_COPY);
    }
    - (NSString *)name{
        return objc_getAssociatedObject(self, &SPNameKey);
    }
    

    方法4:

    #import "Person.h"
    
    @interface Person (Test)
    @property (nonatomic, copy) NSString *name;
    @end
    
    #import "Person+Test.h"
    #import <objc/runtime.h>
    
    @implementation Person (Test)
    
     static const void *SPNameKey = &SPNameKey;
     
     - (void)setName:(NSString *)name {
     objc_setAssociatedObject(self, SPNameKey, name, OBJC_ASSOCIATION_COPY);
     }
     - (NSString *)name{
     return objc_getAssociatedObject(self, SPNameKey);
     }
    

    那么如何添加Button对象?

    代码如下:

    @interface UIView (Test)
    @property (nonatomic, strong) UIButton *hideButton;
    @end
    
    //setter
    - (void)setHideButton:(UIButton *)hideButton {
        objc_setAssociatedObject(self, @selector(hideButton), hideButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    //getter 
    - (UIButton *)hideButton {
        UIButton *_hideButton = objc_getAssociatedObject(self, @selector(hideButton));
        if (!_hideButton) {
            _hideButton = [UIButton buttonWithType:UIButtonTypeCustom];
            _hideButton.frame = CGRectMake(self.bounds.size.width/2-110, 260, 220, 44);
            _hideButton.backgroundColor = [UIColor brownColor];
            [_hideButton setTitle:@"Hide" forState:UIControlStateNormal];
            objc_setAssociatedObject(self, @selector(hideButton), _hideButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        return _hideButton;
    }
    
    

    相关文章

      网友评论

          本文标题:iOS-Runtime-使用关联对象给Category添加成员变

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