iOS - Runtime 动态添加属性
2021-05-15 本文已影响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)