在category
分类中 @property 并不会自动生成实例变量以及存取方法,所以一般使用关联对象为已经存在的类添加 “属性”。使用 objc_getAssociatedObject
以及 objc_setAssociatedObject
来模拟属性的存取方法
在category使用关联对象前首先需要导入<objc/runtime.h>的头文件
#import <objc/runtime.h>
OC中提供的关联对象api
关联对象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)
移除关联的对象
objc_removeAssociatedObjects(id _Nonnull object)
参数意义
-
object
被关联的对象 也就是对象的主分支 -
key
key值 , key与关联的对象是一一对应关系。必须全局唯一。通常使用方式有@selector(methodName)
关联方法对象 或 使用&自定义KEY
或(__bridge const void *)(自定义KEY )
绑定自定义静态KEY值 -
value
要关联的对象或值 -
policy
关联策略
objc_AssociationPolicy policy
有五种关联策略,视同nonatomic
和 strong
等修饰符
/**
* Policies related to associative references.
* These are options to objc_setAssociatedObject()
*/
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
关联策略 objc_AssociationPolicy policy | 等同的修饰符 |
---|---|
OBJC_ASSOCIATION_ASSIGN | @property(weak) |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | @property(strong, nonatomic) |
OBJC_ASSOCIATION_COPY_NONATOMIC | @property(copy, nonatomic) |
OBJC_ASSOCIATION_RETAIN | @property(strong,atomic) |
OBJC_ASSOCIATION_COPY | @property(copy, atomic) |
示例代码
#import <objc/runtime.h>
@implementation UITextField (LengthLimit)
static NSString *kLimitTextLengthKey = @"kLimitTextLengthKey";
- (void)setMaxLength:(int)length {
objc_setAssociatedObject(self, (__bridge const void *)(kLimitTextLengthKey), [NSNumber numberWithInt:length], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self addTarget:self action:@selector(textFieldMaxLengthLimit:) forControlEvents:UIControlEventEditingChanged];
}
- (void)textFieldMaxLengthLimit:(id)textField {
NSNumber *lengthNumber = objc_getAssociatedObject(self, (__bridge const void *)(kLimitTextLengthKey));
int maxLength = [lengthNumber intValue];
}
_cmd 相关
_cmd 在Objective-C的方法中表示当前方法的selector,正如同self表示当前方法调用的对象实例。
cmd的作用域只在当前方法里,直指当前方法名@selector
#import "NSObject+AssociatedObject.h"
#import <objc/runtime.h>
@implementation NSObject (AssociatedObject)
- (void)setAssociatedObject:(id)associatedObject {
objc_setAssociatedObject(self, @selector(associatedObject), associatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, @selector(associatedObject));
}
这里使用_cmd替换如下方式 二者是同意义
- (id)associatedObject {
return objc_getAssociatedObject(self, _cmd);
}
@end