runtime关联属性示例
前言
在开发中经常需要给已有的类添加方法和属性,但是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:表示弱引用关联,通常是基本数据类型,如
int
、float
,非线程安全 - 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关联属性示例的更多相关文章
- EF自动生成的(T4模板) 关联属性元数据修改
为了实现 T4模板关联属性 不要序列化的问题 就是要在具体的 关联属性上面添加一个元数据 这里利用以前的 Newtonsoft.Json 这个框架为例 效果应该为 就是要在关联属性上面添加元数据 [ ...
- CSS3 变形、过渡、动画、关联属性浅析
一.变形 transform:可以对元素对象进行旋转rotate.缩放scale.移动translate.倾斜skew.矩阵变形matrix.示例: transform: rotate(90deg) ...
- Runtime - 关联对象使用方法及注意点
大家都知道在分类里,可以间接的添加属性,运用runtime关联对象. 如下图,只是声明了btnClickedCount的set, get方法而已 并没有生成_btnClickedCount 成员变量, ...
- iOS之Category关联属性
Objective-C /** 原文件 */ // Person.h #import <Foundation/Foundation.h> @interface Person : NSObj ...
- 【iOS】关联属性存取数据
有时候我们需要在现有的类存放一些额外的信息,通常的做法是继承一个子类,然后定义新增加的属性,然而如果我们为每个需要的类都添加一个类显得太麻烦了,objc提供了一个关联属性的特性,可以给一个对象关联一个 ...
- WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性
原文 WPF/Silverlight深度解决方案:(一)解锁被Storyboard束缚的关联属性 如果您在使用WPF/Silverlight进行相关动画开发中使用了Storyboard,并对关联属性进 ...
- grid 布局 属性示例
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- iOS-button利用block封装按钮事件【runtime 关联】
用block封装最常用的就是网络请求的回调,其实也可以结合category封装button的按钮事件,同时利用runtime的对象关联: UIButton+wkjButton.h 文件 #import ...
- Hibernate映射一对多双向关联关系及部门关联属性
一对多双向关联关系:(Dept/Emp的案例) 既可以根据在查找部门时根据部门去找该部门下的所有员工,又能在检索员工时获取某个员工所属的部门. 步骤如下: 1.构建实体类(部门实体类加set员工集合) ...
随机推荐
- Java 反射 Class类
Java 反射 Class类 @author ixenos 摘要:Class类在反射中的地位.构造Class对象的三种方式.Class对象构造对应类型对象的三种方式 Class类在反射中的地位 位于j ...
- 转:MongoDB介绍及下载与安装
非原创,我也是转载(Here)过来备份一下.关于MongoDB园子里有个系列讲的不错的,点击此处跳转 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系 ...
- MySQL Logs
摘要 一.MySQL日志 1.1 查询日志 1.2 慢查询日志 1.3 错误日志 1.4 二进制日志 一. MySQL日志 MySQL服务器上一共有六种日志:错误日志,查询日志,慢查询日志,二进制日志 ...
- [ An Ac a Day ^_^ ] CodeForces 677B Vanya and Food Processor 模拟
题意: 你有一个榨汁机 还有n个土豆 榨汁机可以容纳h高的土豆 每秒可以榨k高的东西 问按顺序榨完土豆要多久 思路: 直接模拟 一开始以为是最短时间排了个序 后来发现多余了…… #include< ...
- ckeditor 插件
dialog 下面 建立一个 插件.js CKEDITOR.dialog.add("about", function (a) { var aaa = "<form& ...
- Hanoi汉诺塔问题——递归与函数自调用算法
题目描述 Description 有N个圆盘,依半径大小(半径都不同),自下而上套在A柱上,每次只允许移动最上面一个盘子到另外的柱子上去(除A柱外,还有B柱和C柱,开始时这两个柱子上无盘子),但绝不允 ...
- winform/wpf 程序部署
(1):一些发布方式 ClickOnce是什么玩意儿,这个问题嘛,在21世纪的互联网严重发达的时代,估计也没有必要大费奏章去介绍了,弄不好的话,还有抄袭之嫌.因此,有关ClickOnce的介绍,各位朋 ...
- tomcat源码分析(二)启动过程
在Catalina的load方法中,首先初始化Server组件. // Start the new server if (server instanceof Lifecycle) { try { se ...
- 解决没有X11/Xlib.h 的错误
1. 解决没有X11/Xlib.h 的错误Install XLib $sudo apt-get install libx11-dev 2. 提示错误:未找到软件源 解决办法很简单,更换另一个源就行了. ...
- js上拉跳转原理
今天遇到一个需要上拉跳转的地方,其原理跟上拉加载有点类似,代码如下 window.onscroll = function(){ if(getScrollTop() + getClientHeight( ...