对象、消息、运行期--10:runtime关联对象

2023-11-22 08:19:45 浏览数 (2)

关联对象

  • 给某个object关联一个或多个其他对象,这些对象通过“键”来区分,我们可以通过这个键给这个object绑定一个对象,也可以通过键获取objct绑定对象。object身上的一个键就对应一个关联对象,所以我们可以给object关联多个对象。类似字典,把关联到object的值理解为字典中的value,这些value通过key来存取。
  • 设置关联对象时用的键是个“不透明指针”,在设置关联对象时,若想让俩个键匹配到同一个值,则二者必须是完全相同的指针才行。鉴于此,存取关联对象用的key通常是一个静态全局变量。
  • runtime提供了給我们3个API以管理关联对象(存储、获取、移除):
    • objc_setAssociatedObject(object,key,value, objc_AssociationPolicy policy)
    • id objc_getAssociatedObject(object, key)
    • objc_removeAssociatedObjects(id object) 参数: object:被关联的对象 key:关联的key,要求唯一 value:关联的对象 objc_AssociationPolicy policy:内存管理的策略 注: objc_removeAssociatedObjects(id object)函数移除的是某个对象身上的所有关联的对象。objc没有给我们提供移除object身上单个关联对象的函数,所以,一般通过objc_setAssociatedObject函数传入nil来达到移除某个关联对象的目的。 内存管理的策略

关联类型

等效的@property

OBJC_ASSOCIATION_ASSIGN

assign

OBJC_ASSOCIATION_RETAIN_NONATOMIC

nonatomic,retain

OBJC_ASSOCIATION_COPY_NONATOMIC

nonatomic,copy

OBJC_ASSOCIATION_RETAIN

retain

OBJC_ASSOCIATION_COPY

copy

给category的property添加getter和setter

在category中的使用 @property添加属性 ,不会生成带下划线的成员变量,也不会有setter和getter方法实现,所以我们通过runtime关联对象的技术为已经存在的类添加“属性”,这样我们只是实现了setter和getter方法,依然不会有带下划线的成员变量

代码语言:javascript复制
#import "Phone.h"
@interface Phone (Info)
@property (nonatomic,copy) NSString *name;
@end

#import "Phone Info.h"
#import <objc/runtime.h>
//定义常量 必须是C语言字符串
static const char *key = "name";
@implementation Phone (Info)
- (void)setName:(NSString *)name{
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name{
    return objc_getAssociatedObject(self, key);
}
@end


#import "ViewController.h"
#import "Phone.h"
#import "Phone Info.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    Phone *phone = [[Phone alloc]init];
    phone.name = @"I'm iphone";
    NSLog(@"%@",phone.name);
}
@end

log:I'm iphone

给UIButton的category的添加回调方法

代码语言:javascript复制
#import <UIKit/UIKit.h>
typedef void(^ButtonClickCallBack) (UIButton *button);
@interface UIButton (Base)
- (void)handleClickCallBack:(ButtonClickCallBack)callBack;
@end

#import "UIButton Base.h"
#import <objc/runtime.h>
static const char *key = "Click";
@implementation UIButton (Base)
- (void)handleClickCallBack:(ButtonClickCallBack)callBack{

    objc_setAssociatedObject(self, key, callBack, OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
}

- (void)buttonClicked{
    ButtonClickCallBack callBack = objc_getAssociatedObject(self, key);
    if (callBack) {
        callBack(self);
    }
}
@end

#import "ViewController.h"
#import "UIButton Base.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [button setFrame:CGRectMake(100, 100, 100, 100)];
    [button handleClickCallBack:^(UIButton *button) {
        NSLog(@"button clicked");
    }];
    [self.view addSubview:button];
 }
@end

log: button clicked

参考

Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法

0 人点赞