category与associative作为objective-c的扩展机制的两个特性,category即类型,可以通过它来扩展方法;associative,可以通过它来扩展属性;在iOS开发中,可能category比较常见,相对的associative,就用的比较少,要用它必须使用<objc/runtime.h>的头文件,然后就可以自由使用objc_getAssociatedObject以及objc_setAssociatedObject

对象关联(或称关联引用)本来是Objective-C 2.0运行时的一个特性,起始于OS X Snow Leopard和iOS 4。相关参考可以查看 <objc/runtime.h> 中定义的以下三个允许你将任何键值在运行时关联到对象上的函数:

  • objc_setAssociatedObject
  • objc_getAssociatedObject
  • objc_removeAssociatedObjects

NSObject+AssociatedObject.h

@interface NSObject (AssociatedObject)
@property (nonatomic, strong) id associatedObject;
@end

NSObject+AssociatedObject.m

@implementation NSObject (AssociatedObject)
@dynamic associatedObject; - (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} - (id)associatedObject {
return objc_getAssociatedObject(self, @selector(associatedObject));
}

通常推荐的做法是添加的属性最好是static char 类型的,当然更推荐是指针型的.通常来说该属性应该是常量,唯一的,在适用范围内用getter和setter访问到

关联对象的行为

属性可以根据定义在枚举类型 objc_AssociationPolicy 上的行为被关联在对象上:

Behavior @property Equivalent Description
OBJC_ASSOCIATION_ASSIGN @property (assign) 或@property (unsafe_unretained) 指定一个关联对象的弱引用。
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (nonatomic, strong) 指定一个关联对象的强引用,不能被原子化使用。
OBJC_ASSOCIATION_COPY_NONATOMIC @property (nonatomic, copy) 指定一个关联对象的copy引用,不能被原子化使用。
OBJC_ASSOCIATION_RETAIN @property (atomic, strong) 指定一个关联对象的强引用,能被原子化使用。
OBJC_ASSOCIATION_COPY @property (atomic, copy) 指定一个关联对象的copy引用,能被原子化使用。

以 OBJC_ASSOCIATION_ASSIGN 类型关联在对象上的弱引用不代表0 retian的 weak 弱引用,行为上更像unsafe_unretained 属性,所以当在你的视线中调用weak的关联对象时要相当小心。

根据WWDC 2011, Session 322 (第36分钟左右)发布的内存销毁时间表,被关联的对象在生命周期内要比对象本身释放的晚很多。它们会在被 NSObject -dealloc 调用的object_dispose() 方法中释放。

删除属性

你可以会在刚开始接触对象关联时想要尝试去调用 objc_removeAssociatedObjects() 来进行删除操作,但如文档中所述,你不应该自己手动调用这个函数:

此函数的主要目的是在“初试状态”时方便地返回一个对象。你不应该用这个函数来删除对象的属性,因为可能会导致其他客户对其添加的属性也被移除了。规范的方法是:调用 objc_setAssociatedObject 方法并传入一个 nil 值来清除一个关联。

优秀样例

  • 添加私有属性用于更好地去实现细节。当扩展一个内建类的行为时,保持附加属性的状态可能非常必要。注意以下说的是一种非常教科书式的关联对象的用例:AFNetworking在 UIImageView 的category上用了关联对象来保持一个operation对象,用于从网络上某URL异步地获取一张图片。
  • 添加public属性来增强category的功能。有些情况下这种(通过关联对象)让category行为更灵活的做法比在用一个带变量的方法来实现更有意义。在这些情况下,可以用关联对象实现一个一个对外开放的属性。回到上个AFNetworking的例子中的 UIImageViewcategory,它的 imageResponseSerializer方法允许图片通过一个滤镜来显示、或在缓存到硬盘之前改变图片的内容。
  • 创建一个用于KVO的关联观察者。当在一个category的实现中使用KVO时,建议用一个自定义的关联对象而不是该对象本身作观察者。ng an associated observer for KVO**. When using KVO in a category implementation, it is recommended that a custom associated-object be used as an observer, rather than the object observing itself.

反例

  • 当值不需要的时候建立一个关联对象。一个常见的例子就是在view上创建一个方便的方法去保存来自model的属性、值或者其他混合的数据。如果那个数据在之后根本用不到,那么这种方法虽然是没什么问题的,但用关联到对象的做法并不可取。
  • 当一个值可以被其他值推算出时建立一个关联对象。例如:在调用cellForRowAtIndexPath: 时存储一个指向view的 UITableViewCell 中accessory view的引用,用于在 tableView:accessoryButtonTappedForRowWithIndexPath: 中使用。
  • 用关联对象替代X,这里的X可以代表下列含义:
    • 当继承比扩展原有的类更方便时用子类化。
    • 为事件的响应者添加响应动作。
    • 当响应动作不方便使用时使用的手势动作捕捉。
    • 行为可以在其他对象中被代理实现时要用代理(delegate)。
    • 用NSNotification 和 NSNotificationCenter进行松耦合化的跨系统的事件通知。 * * *

比起其他解决问题的方法,关联对象应该被视为最后的选择(事实上category也不应该作为首选方法)。

对象关联(associated objects)的更多相关文章

  1. JS 中通过对象关联实现『继承』

    JS 中继承其实是种委托,而不是传统面向对象中的复制父类到子类,只是通过原型链将要做的事委托给父类. 下面介绍通过对象关联来实现『继承』的方法: Foo = { // 需要提供一个 init 方法来初 ...

  2. Grails 对象关联映射 (GORM) 一

    转自:http://justjavac.iteye.com/blog/701445 Domain 类是任何商业应用的核心. 他们保存事务处理的状态,也处理预期的行为. 他们通过关联联系在一起, one ...

  3. 实例:ABAP Tree Control 使用与ALV Grid对象关联

    Tree Control 是最常用的Windows控件之一,在其他语言中成为"Tree View"等,ABAP的 Tree Contiol 能实现类似的功能. 本文主要介绍一下内容 ...

  4. JavaSE基础知识(5)—面向对象(对象数组和对象关联)

    一.对象数组 1.说明 数组的定义类型为对象类型 2.动态初始化 1.声明并开辟空间 Person[] pers = new Person[长度];2.赋值 for(int i=0;i<pers ...

  5. ABAP CDS 替换对象(Replacement Objects)引起的数据错误

    最近遇到了一个诡异的问题:从CDS视图中取得的数据,和从透明表中取得的数据,会有不同的值.在这里记录下问题的表现和解决方案,以供参考. 系统版本:S/4HANA OP1610 涉及表:MCHB 本文链 ...

  6. void bind(String sName,Object object);――绑定:把名称同对象关联的过程

    void bind(String sName,Object object);――绑定:把名称同对象关联的过程 void rebind(String sName,Object object);――重新绑 ...

  7. Java中如何创建一个新的对象的/Creating Objects/

    The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't ...

  8. ORM SQLAlchemy - 对象关联

    >>> from sqlalchemy import Column, Integer, String >>> class User(Base): ... __tab ...

  9. Mongodb内嵌对象关联查询

    db.-10-30T00:00:00Z"),"$lt":ISODate("2018-10-30T23:59:00Z")}, "equip.$ ...

随机推荐

  1. mongo创建用户

    use dwb db.createUser( { "user" : "username",                         "pwd& ...

  2. php本地及远程文件包含漏洞

    在php程序中包含有file inclusion的时候,php要开启一下两个功能: allow_url_fopen onallow_url_include on 但是开启这两个功能之后伴随的是url漏 ...

  3. android-webview开发中的各种使用方法(持续更,尽量全)

    最新坑A:(没看过的可以从下面开始处看起): 测试部门测出来一个坑,当多次点击退出后,会出现app崩溃现象,报如下错误: java.lang.IllegalArgumentException: Rec ...

  4. c语言问卷

    1.你对自己的未来有什么规划?做了哪些准备? 答:关于未来我想从事设计网页.做小游戏或者app的工作,因为是金融服务外包方向,也许也会进入银行或者证券公司管理银行系统.让英语更近一层,可进入外企工作. ...

  5. linux内核学习之三 跟踪分析内核的启动过程

    一   前期准备工作       1 搭建环境 1.1下载内核源代码并编译内核 创建目录,并进入该目录: 下载源码: 解压缩,并进入该目录:xz -d linux-3.18.6.tar.xz tar ...

  6. 利用HttpURLConnection发送请求

    HttpURLConnection: 每个 HttpURLConnection实例都可用于生成单个请求,但是其他实例可以透明地共享连接到 HTTP 服务器的基础网络.请求后在 HttpURLConne ...

  7. iOS 指定圆角个数

    需要实现的效果很明确,只要左上和右上两个地方圆角,以前都是通过layer 直接设置四个角都变成圆角,然后我就开始了强大的搜索功能 然后我就获得了我想要的东西 技术链接:http://www.xuebu ...

  8. reinstall ubuntu

    flickering mouse issue http://askubuntu.com/questions/310341/do-graphics-drivers-for-intel-hd-4600-e ...

  9. 浅谈大数据神器Spark中的RDD

    1.究竟什么是RDD呢? 有人可能会回答是:Resilient Distributed Dataset.没错,的确是如此.但是我们问这个实际上是想知道RDD到底是个什么东西?以及它到底能干嘛?好的,有 ...

  10. Android深度探索--HAL与驱动开发----第七章读书笔记

    首先创建led驱动的设备文件,可以使用cdev_init,register_chrdev_region,cdev_add等建立主设备号的设备文件.步骤如下: 1使用cdev_init初始化cdev 2 ...