美文网首页iOS
iOS通过runtime给分类添加属性

iOS通过runtime给分类添加属性

作者: _清墨 | 来源:发表于2019-03-27 13:38 被阅读0次
    分类Category可以添加方法,但不能直接添加属性,如下,我们创建一个UIImage的Category: WX20190327-130805@2x.png
    WX20190327-130820@2x.png

    咱们直接输入一个Url,最终得到的是:


    image.png

    这样一个分类,我们给其添加一个属性:

    @property (nonatomic, copy) NSString *imageUrl;
    

    这是编译一下,会报如下警告


    image.png

    而且如果这时在外部使用这个属性,运行会crash,并会报如下错误

    调用set方法时
    2019-03-27 13:18:03.497364+0800 Target[98782:2455630] *** 
    Terminating app due to uncaught exception 'NSInvalidArgumentException', 
    reason: '-[UIImage setImageUrl:]: 
    unrecognized selector sent to instance 0x600002bc8ee0'
    
    调用get方法时
    2019-03-27 13:19:49.208647+0800 Target[98819:2456879] *** 
    Terminating app due to uncaught exception 'NSInvalidArgumentException', 
    reason: '-[UIImage imageUrl]: 
    unrecognized selector sent to instance 0x600002950230'
    

    原因就是这个分类属性找不到set和get方法,若要能正常使用这个属性的set和get方法,我们可以通过runtime来做到:

    首先我们在.m里

    #import <objc/runtime.h>
    

    然后重写set和get方法

    -(void)setImageUrl:(NSString *)imageUrl{
        
    }
    
    -(NSString *)imageUrl{
        
    }
    

    这时需要了解的函数是

    //set
    objc_setAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>, <#id  _Nullable value#>, <#objc_AssociationPolicy policy#>)
    //get
    objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
    

    set有四个参数,get的参数可以参考set
    1.源对象(self)
    2.关联时的用来标记的key(因为可能会添加很多属性,我们这里是imageUrl,所以也需要一个imageUrl的key:& imageUrl_key)

    //我们需要在.m里声明这个key
    static NSString *imageUrl_key = @"imageUrl_key";
    

    3.关联的对象(imageUrl)
    4.一个关联策略(OBJC_ASSOCIATION_COPY)。

    typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
        OBJC_ASSOCIATION_ASSIGN = 0,             //关联对象的属性是弱引用    
        OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,   //关联对象的属性是强引用并且关联对象不使用原子性
        OBJC_ASSOCIATION_COPY_NONATOMIC = 3,     //关联对象的属性是copy并且关联对象不使用原子性
        OBJC_ASSOCIATION_RETAIN = 01401,         //关联对象的属性是copy并且关联对象使用原子性
        OBJC_ASSOCIATION_COPY = 01403            //关联对象的属性是copy并且关联对象使用原子性
    };
    

    最终的set和get方法是这样的

    -(void)setImageUrl:(NSString *)imageUrl{
        objc_setAssociatedObject(self, &imageUrl_key, imageUrl, OBJC_ASSOCIATION_COPY);
    }
    
    -(NSString *)imageUrl{
        return objc_getAssociatedObject(self, &imageUrl_key);
    }
    

    这时在外部就能正常使用这个属性:

    UIImage *image = [[UIImage alloc]init];
    image.imageUrl = @"www.999999.com";
        
    NSString *url = image.imageUrl;
    

    相关文章

      网友评论

        本文标题:iOS通过runtime给分类添加属性

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