美文网首页
iOS - Runtime 动态添加属性

iOS - Runtime 动态添加属性

作者: 码代码的小马 | 来源:发表于2021-05-15 23:31 被阅读0次

    我们在开发中常常使用类目Category为一些已有的类扩展功能。虽然继承也能够为已有类增加新的方法,而且相比类目更是具有增加属性的优势,但是继承毕竟是一个重量级的操作,添加不必要的继承关系无疑增加了代码的复杂度。

    遗憾的是,OC的类目并不支持直接添加属性,如果我们直接在分类的声明中写入Property属性,那么只能为其生成set与get方法声明,却不能生成成员变量,直接调用这些属性还会造成崩溃。

    所以为了实现给分类添加属性,我们还需借助Runtime的关联对象(Associated Objects)特性,它能够帮助我们在运行阶段将任意的属性关联到一个对象上,下面是相关的三个方法:

    usr/include/runtime.h

    /** 
     * Sets an associated value for a given object using a given key and association policy.
     * 
     * @param object The source object for the association.
     * @param key The key for the association.
     * @param value The value to associate with the key key for object. Pass nil to clear an existing association.
     * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
     * 
     * @see objc_setAssociatedObject
     * @see objc_removeAssociatedObjects
     */
    OBJC_EXPORT void
    objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                             id _Nullable value, objc_AssociationPolicy policy)
        OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
    
    /** 
     * Returns the value associated with a given object for a given key.
     * 
     * @param object The source object for the association.
     * @param key The key for the association.
     * 
     * @return The value associated with the key \e key for \e object.
     * 
     * @see objc_setAssociatedObject
     */
    OBJC_EXPORT id _Nullable
    objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
        OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
    
    /** 
     * Removes all associations for a given object.
     * 
     * @param object An object that maintains associated objects.
     * 
     * @note The main purpose of this function is to make it easy to return an object 
     *  to a "pristine state”. You should not use this function for general removal of
     *  associations from objects, since it also removes associations that other clients
     *  may have added to the object. Typically you should use \c objc_setAssociatedObject 
     *  with a nil value to clear an association.
     * 
     * @see objc_setAssociatedObject
     * @see objc_getAssociatedObject
     */
    OBJC_EXPORT void
    objc_removeAssociatedObjects(id _Nonnull object)
        OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
    
    

    注意:key与关联属性一一对应,我们必须确保其全局唯一性,通常我们使用@selector(methodName)做为key.

    以下为示例代码:为UIImage添加一个分类:UIImage+Tools,并为其设置urlString(图片网络链接属性)

    @interface UIImage (Tool)
    
    @property (nonatomic, copy) NSString *urlString;
    
    - (void)clearAssociatedObject;
    
    @end
    
    //
    //  UIImage+Tool.m
    //  LoadInitializeDemo
    //
    //  Created by Ternence on 2021/5/12.
    //
    
    #import "UIImage+Tool.h"
    #import <objc/runtime.h>
    
    
    @implementation UIImage (Tool)
    
    - (void)setUrlString:(NSString *)urlString {
        objc_setAssociatedObject(self, @selector(urlString), urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)urlString {
        return objc_getAssociatedObject(self, @selector(urlString));
    }
    
    - (void)clearAssociatedObject {
        objc_removeAssociatedObjects(self);
    }
    
    @end
    
    

    测试调用:

        UIImage *image = [[UIImage alloc] init];
        image.urlString = @"http://www.baidu.com";
        NSLog(@"=====urlString: %@", image.urlString);
        [image clearAssociatedObject];
        NSLog(@"=======urlString: %@",image.urlString);
    

    打印输出:

    2021-05-12 16:26:02.880219+0800 LoadInitializeDemo[98906:3244158] =====urlString: http://www.baidu.com
    2021-05-12 16:26:02.880376+0800 LoadInitializeDemo[98906:3244158] =======urlString: (null)
    

    相关文章

      网友评论

          本文标题:iOS - Runtime 动态添加属性

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