博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Objective-C——关联对象
阅读量:5273 次
发布时间:2019-06-14

本文共 3752 字,大约阅读时间需要 12 分钟。

动态语言

OC是一种动态语言,它的方法,对象的类型都是到运行的时候才能够确定的。所以这就使得OC存在了关联对象这一强大的机制。

 

关联对象

所谓关联对象,其实就是我们在运行时对一个已存在的对象上面绑定一个对象,使两个对象变成动态的聚合关系。

关联对象和属性一样有着关键字,以下是关联对象的存储策略:

关联类型 等效的@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

 

 

 

 

 

 

关联对象主要靠下面三个函数,它们都位于<objc/runtime>下

void objc_setAssociatedObject(id object, void *key ,id value ,objc_AssociationPolicy policy)

设置关联对象

参数 说明
object 要进行关联的对象
key 一个内存表示,在比较两个关联对象是否相等时,比较的就是内存地址,所以一般用一个全局静态变量表示
value 被关联的对象
policy 存储策略

 

 

 

 

 

id objc_getAssociatedObject(id object, void *key)

获取关联对象

void objc_removeAssociatedObjects(id object)

删除关联对象

 

作用

关联对象一般用于动态的扩展一个对象,但是这一般都是在其他方法不行的事后才会使用,因为关联对象很可能会出现难以查找的bug。

关联对象有时也会用于在category向类添加属性,这点等会儿在分析。

下面Demo在UIAlertView上面动态绑定了一个block,把按钮处理逻辑和alert调用整合在了一起。

static char *AlertKey = "alertKey";- (void)viewDidLoad {    [super viewDidLoad];       alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];}- (IBAction)click:(id)sender {        void (^block) (NSInteger) = ^(NSInteger buttonIndex){        if (buttonIndex == 0){            NSLog(@"click cancel");        }        else{            NSLog(@"click other");        }    };    objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY);    [alert show];}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{    void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey);    block(buttonIndex);}

运行程序点击两个按钮分别输出如下

2015-08-11 22:51:27.146 Dynamic[4592:2833778] click other2015-08-11 22:51:28.262 Dynamic[4592:2833778] click cancel

 

接下来我们给UIViewController在category中添加一个addition属性

#import "ViewController.h"#import 
@interface UIViewController (Addition)@property(nonatomic ,copy) NSString *addition;@end
#import "UIViewController+Addition.h"static const void *IndieBandNameKey = &IndieBandNameKey;@implementation UIViewController (Addition)-(void)setAddition:(NSString *)addition{    objc_setAssociatedObject(self, IndieBandNameKey, addition, OBJC_ASSOCIATION_COPY);}-(NSString *)addition{    return objc_getAssociatedObject(self, IndieBandNameKey);}@end

这里说明一下,这里关联的实际上是形参addition,和属性没有什么关系,写@property 就是为了能够使用‘.’语法。但是@porperty里面的属性存储策略还是要和关联对象一致的,这样不容易造成误解。

所以每次setAddition实际上我们并不是修改了原有内存的值,而是改变了指针指向的地址,这里需要注意一下。

然后修改刚才alert的代码

- (void)viewDidLoad {    [super viewDidLoad];       alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];    alert.delegate = self;    self.addition = @"addition";    }- (IBAction)click:(id)sender {        void (^block) (NSInteger) = ^(NSInteger buttonIndex){        if (buttonIndex == 0){            NSLog(@"click cancel");            objc_removeAssociatedObjects(self);        }        else{            NSLog(@"click other");            NSLog(@"%@",self.addition);        }    };    objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY);    [alert show];}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{    void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey);    block(buttonIndex);}

注意三条加粗的语句,然后我们运行看结果

2015-08-11 22:53:54.353 Dynamic[4655:2849502] click other2015-08-11 22:53:54.353 Dynamic[4655:2849502] addition2015-08-11 22:53:55.804 Dynamic[4655:2849502] click cancel2015-08-11 22:53:57.491 Dynamic[4655:2849502] click other2015-08-11 22:53:57.491 Dynamic[4655:2849502] (null)

首先我们使用了关联对象,所以点击other的时候会看到打印出了addition。点击cancel的时候又因为我们remove了关联对象,此时再点击other的时候addition就变成null了。

转载于:https://www.cnblogs.com/madpanda/p/4722602.html

你可能感兴趣的文章
从C#到Objective-C,循序渐进学习苹果开发(1)--准备开发账号和开发环境
查看>>
视图的定义、更新、撤销
查看>>
iOS之页面传值-----单例传值、通知传值
查看>>
数组换位子
查看>>
软件测试草图
查看>>
一个App项目设计开发完整流程
查看>>
如何使用iClap创建普通批注
查看>>
用Java编写自己的机器人,为你承担苦力
查看>>
第四章App4_3,懂得了抛出异常 throws Exception,read为读取键盘输入数,学会了switch循环...
查看>>
从零开始——MySql01
查看>>
基于线程池的线程管理(BlockingQueue生产者消费者方式)实例
查看>>
sqlmap
查看>>
给出随机存储器(RAM)和只读存储器(ROM)的差别
查看>>
CSS3 3D Transform
查看>>
js深拷贝
查看>>
http和socket之长连接和短连接区别(转)
查看>>
【HTML】网页中如何让DIV在网页滚动到特定位置时出现
查看>>
文件序列化
查看>>
C++11 中的线程、锁和条件变量
查看>>
HDU 2485 Destroying the bus stations(!最大流∩!费用流∩搜索)
查看>>