我们在开发中常常使用类目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)