Objective-C——关联对象

动态语言

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];
    alert.delegate = self;
}

- (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 other
2015-08-11 22:51:28.262 Dynamic[4592:2833778] click cancel

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

#import "ViewController.h"
#import <objc/runtime.h>

@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 other
2015-08-11 22:53:54.353 Dynamic[4655:2849502] addition
2015-08-11 22:53:55.804 Dynamic[4655:2849502] click cancel
2015-08-11 22:53:57.491 Dynamic[4655:2849502] click other
2015-08-11 22:53:57.491 Dynamic[4655:2849502] (null)

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

时间: 2024-10-29 10:47:47

Objective-C——关联对象的相关文章

iOS关联对象

Associated Objects(关联对象)或者叫作关联引用(Associative References),是作为Objective-C 2.0 运行时功能被引入到 Mac OS X 10.6 Snow Leopard(及iOS4)系统.与它相关在<objc/runtime.h>中有3个C函数,它们可以让对象在运行时关联任何值: OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value,

关联对象

一.关联对象所用的方法主要有两个: 1>设置关联对象值:objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 2>根据Key取出关联对象的关联值:objc_getAssociatedObject(id object, const void *key) 其中: object:关联的对象, key存和取关联值的键, objc_AssociationPolicy po

iOS-runtime-objc_setAssociatedObject(关联对象以及传值)

例子: static const char kRepresentedObject; - (IBAction)doSomething:(id)sender { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; objc_setAssociate

hibernate关联对象的增删改查------查

本篇博客是之前博客hibernate关联对象的增删改查------查 的后继,本篇代码的设定都在前文已经写好,因此读这篇之前,请先移步上一篇博客 //代码片5 SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); Session session = sessionFactory.getCurrentSession(); session.beginTransa

iOS objc_setAssociatedObject 关联对象的学习

今天看了FDTemplateLayoutCell的源码,类别里面相当频繁使用了关联对象,做笔记!!!学套路 主要函数: void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy); id objc_getAssociatedObject(id object, const void *key); void objc_removeAssociatedObjects

关联对象和objc_msgSend

关联对象,其实就是给某个对象关联其他一些对象,这些对象通过键来设置和存储,并且存储对象值得时候可以设置存储策略,常用在类别中 比如我们给UIButton创建一个类别,不用将button处理的事件分开写了 2.消息传递 OC是C的超集,C语言使用的是静态绑定,在编译期就能决定运行时候调用的函数,而OC在给对象传递消息的时候,是利用动态绑定来决定所要调用的方法,是在运行期才知道该调用的方法,甚至可以在运行期改变方法,这使得OC是一门及其动态的语言 3.消息转发 这里涉及到一个问题就是,当某个对象接收

Runtime之成员变量&amp;属性&amp;关联对象

上篇介绍了Runtime类和对象的相关知识点,在4.5和4.6小节,也介绍了成员变量和属性的一些方法应用.本篇将讨论实现细节的相关内容. 在讨论之前,我们先来介绍一个很冷僻但又很有用的一个关键字:@encode 1.类型编码 为了协助运行时系统,编译器用字符串为每个方法的返回值.参数类型和方法选择器编码,使用的编码方案在其他情况下也很有用.在 Objective-C 运行时的消息发送机制中,传递参数时,由于类型信息的缺失,需要类型编码进行辅助以保证类型信息也能够被传递.在实际的应用开发中,使用案

mybatis中的关联对象查询

方式1(嵌套查询): 在本类的mapper映射配置文件中的ResultMap标签中使用association子标签,对关联对象的属性进行关联 例如:User中关联Department(多对一) ----------User的mapper映射配置文件---------<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Map

Associated Objects(关联对象)

#import <objc/runtime.h> Objective-C开发者应该小心谨慎地遵循这个危险咒语的各种准则.一个很好的原因的就是:混乱的运行时代码会改变运行在其架构之上的所有代码. 从利的角度来讲, <objc/runtime.h> 中的函数具有其他方式做不到的.能为应用和框架提供强大功能的能力.而从弊的角度来讲,它可能会会毁掉代码的sanity meter,一切代码和逻辑都可能被异常糟糕的副作用影响(terrifying side-effects). 因此,我们怀着巨