前言

在开发中经常需要给已有的类添加方法和属性,但是Objective-C是不允许给已有类通过分类添加属性的,因为类分类是不会自动生成成员变量的。但是,我们可以通过运行时机制就可以做到了。

本篇文章适合新手阅读,手把手教你如何在项目中使用关联属性!

API介绍

我们先看看Runtime提供的关联API,只有这三个API,使用也是非常简单的:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 
/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
 
/**
* Returns the value associated with a given object for a given key.
*
* @param object The source object for the association.
* @param key The key for the association.
*
* @return The value associated with the key \e key for \e object.
*
* @see objc_setAssociatedObject
*/
id objc_getAssociatedObject(id object, const void *key)
 
/**
* Removes all associations for a given object.
*
* @param object An object that maintains associated objects.
*
* @note The main purpose of this function is to make it easy to return an object
*  to a "pristine state”. You should not use this function for general removal of
*  associations from objects, since it also removes associations that other clients
*  may have added to the object. Typically you should use \c objc_setAssociatedObject
*  with a nil value to clear an association.
*
* @see objc_setAssociatedObject
* @see objc_getAssociatedObject
*/
void objc_removeAssociatedObjects(id object)
 

实际上,我们几乎不会使用到objc_removeAssociatedObjects函数,这个函数的功能是移除指定的对象上所有的关联。既然我们要添加关联属性,几乎不会存在需要手动取消关联的场合。

设置关联值(Setter)

对于设置关联,我们需要使用下面的API关联起来:

 
1
2
3
 
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
 

参数说明:

  • object:与谁关联,通常是传self
  • key:唯一键,在获取值时通过该键获取,通常是使用static const void *来声明
  • value:关联所设置的值
  • policy:内存管理策略,比如使用copy

获取关联值(Getter)

如果我们要获取所关联的值,需要通过key来获取,调用如下函数:

 
1
2
3
 
id objc_getAssociatedObject(id object, const void *key)
 

参数说明:

  • object:与谁关联,通常是传self,在设置关联时所指定的与哪个对象关联的那个对象
  • key:唯一键,在设置关联时所指定的键

关联策略

我们先看看设置关联时所指定的policy,它是一个枚举类型,看官方说明:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
/**
* 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_ASSOCIATION_ASSIGN:表示弱引用关联,通常是基本数据类型,如intfloat,非线程安全
  • OBJC_ASSOCIATION_RETAIN_NONATOMIC:表示强(strong)引用关联对象,非线程安全
  • OBJC_ASSOCIATION_COPY_NONATOMIC:表示关联对象copy,非线程安全
  • OBJC_ASSOCIATION_RETAIN:表示强(strong)引用关联对象,是线程安全的
  • OBJC_ASSOCIATION_COPY:表示关联对象copy,是线程安全的

扩展属性

我们来写一个例子,扩展UIControl添加Block版本的TouchUpInside事件。

扩展头文件声明:

1
2
3
4
5
6
7
8
9
10
11
 
#import <UIKit/UIKit.h>
 
typedef void (^HYBTouchUpBlock)(id sender);
 
@interface UIControl (HYBBlock)
 
@property (nonatomic, copy) HYBTouchUpBlock hyb_touchUpBlock;
 
@end
 

扩展实现文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
#import "UIControl+HYBBlock.h"
#import <objc/runtime.h>
 
static const void *sHYBUIControlTouchUpEventBlockKey = "sHYBUIControlTouchUpEventBlockKey";
 
@implementation UIControl (HYBBlock)
 
- (void)setHyb_touchUpBlock:(HYBTouchUpBlock)hyb_touchUpBlock {
  objc_setAssociatedObject(self,
                           sHYBUIControlTouchUpEventBlockKey,
                           hyb_touchUpBlock,
                           OBJC_ASSOCIATION_COPY);
  
  [self removeTarget:self
              action:@selector(hybOnTouchUp:)
    forControlEvents:UIControlEventTouchUpInside];
  
  if (hyb_touchUpBlock) {
    [self addTarget:self
             action:@selector(hybOnTouchUp:)
   forControlEvents:UIControlEventTouchUpInside];
  }
}
 
- (HYBTouchUpBlock)hyb_touchUpBlock {
  return objc_getAssociatedObject(self, sHYBUIControlTouchUpEventBlockKey);
}
 
- (void)hybOnTouchUp:(UIButton *)sender {
  HYBTouchUpBlock touchUp = self.hyb_touchUpBlock;
  
  if (touchUp) {
    touchUp(sender);
  }
}
 
@end
 

runtime关联属性示例的更多相关文章

  1. EF自动生成的(T4模板) 关联属性元数据修改

    为了实现 T4模板关联属性 不要序列化的问题 就是要在具体的 关联属性上面添加一个元数据 这里利用以前的 Newtonsoft.Json 这个框架为例 效果应该为 就是要在关联属性上面添加元数据  [ ...

  2. CSS3 变形、过渡、动画、关联属性浅析

    一.变形 transform:可以对元素对象进行旋转rotate.缩放scale.移动translate.倾斜skew.矩阵变形matrix.示例: transform: rotate(90deg) ...

  3. Runtime - 关联对象使用方法及注意点

    大家都知道在分类里,可以间接的添加属性,运用runtime关联对象. 如下图,只是声明了btnClickedCount的set, get方法而已 并没有生成_btnClickedCount 成员变量, ...

  4. iOS之Category关联属性

    Objective-C /** 原文件 */ // Person.h #import <Foundation/Foundation.h> @interface Person : NSObj ...

  5. 【iOS】关联属性存取数据

    有时候我们需要在现有的类存放一些额外的信息,通常的做法是继承一个子类,然后定义新增加的属性,然而如果我们为每个需要的类都添加一个类显得太麻烦了,objc提供了一个关联属性的特性,可以给一个对象关联一个 ...

  6. WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性

    原文 WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性 如果您在使用WPF/Silverlight进行相关动画开发中使用了Storyboard,并对关联属性进 ...

  7. grid 布局 属性示例

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  8. iOS-button利用block封装按钮事件【runtime 关联】

    用block封装最常用的就是网络请求的回调,其实也可以结合category封装button的按钮事件,同时利用runtime的对象关联: UIButton+wkjButton.h 文件 #import ...

  9. Hibernate映射一对多双向关联关系及部门关联属性

    一对多双向关联关系:(Dept/Emp的案例) 既可以根据在查找部门时根据部门去找该部门下的所有员工,又能在检索员工时获取某个员工所属的部门. 步骤如下: 1.构建实体类(部门实体类加set员工集合) ...

随机推荐

  1. CentOS/RedHat rpm方式安装Apache2.2

    注:所有RPM包均从网易镜像上下载 # rpm -ivh /home/apache/apr-1.3.9-5.el6_2.x86_64.rpm warning: /home/apache/apr-1.3 ...

  2. Redis持久存储-AOF&RDB

    Redis中数据存储模式有2种:cache-only,persistence;cache-only即只做为"缓存"服务,不持久数据,数据在服务终止后将消失,此模式下也将不存在&qu ...

  3. Chapter7 迭代器

    结合泛型for的所有功能,写出更加简单,高效的迭代器. 1.迭代器和closure 迭代器是一种可以遍历集合中所有元素的机制.在Lua中用函数去表示它. 每调用一次,就返回下一个元素. 迭代器在两次成 ...

  4. 大数据加减(Big data addition and subtraction)

    题目描述 Description 加减法是计算中的基础运算,虽然规则简单,但是位数太多了,也难免会出错.现在的问题是:给定任意位数(不超过1000位)的加减法算式,请给出正确结果.为提高速度,保证给定 ...

  5. ubuntu下的ssh工具gstm

    (转自:http://www.nenew.net/ubuntu-ssh-gstm.html) 首先安装: sudo apt-get install gstm 就可以安装,当然你也可以到http://s ...

  6. 基于Flash ActionScript 实现RTMP发布与播放媒本流

    1  为什么要采用Flash ActionScript实现RTMP协议发布或播放媒体流,播放媒体流,协议可控,比如对流媒体数加密,混音等. 2 核心思路使用Flash Socket建立TCP二进制传输 ...

  7. java 常用的三大集合类

    一.Set集合.其主要实现类有HashSet.TreeSet.存放对象的引用,不允许有重复对象. 代码: public class SetTest { public static void main( ...

  8. android 常用

    1:常用之动画(View Animation,Drawable Animation,Property Animation) http://blog.csdn.net/huxueyan521/artic ...

  9. C# 处理图片 不规则图形裁剪

    最近项目要求实现不规则裁剪功能.本来想用html5的canvas在前端实现的,但是发现有点困难,以下为C#端对图对片的处理. 为了让大家知道下面内容是否是自己想要的,我先发效果图. 原图 通过下面代码 ...

  10. ios电话监听状态

    #import "ViewController.h" #import <CoreTelephony/CTCallCenter.h> #import <CoreTe ...