Runtime的实践——给一个类添加属性(关联对象)

相关文章:

《Runtime的初步认识——结构体与类》

《Runtime的初步认识——消息机制》

一提到给一个类添加点什么,我们有可能首先就想到类别(Category)。那么我们就弄一下。

利用 Category 给现有的类添加属性

比如我们要给一个 NSArray 添加一个属性叫做NSString *name。

我们首先新建一个Objective-C文件。

File: Name

File Type:Category

Class:NSArray

然后我们在NSArray+Name.h里面写

@interface NSArray (Name)

@property (nonatomic, copy) NSString *name;

@end

于是我们就给NSArray这个类添加了一个NSString类型的name

现在我们导入NSArray+Name.h文件去实现一下代码验证一下

NSArray *array = [[NSArray alloc] init];

array.name = @"test";

NSLog(@"%@", array.name);

我们新建了一个NSArray,并把@"test"赋值给了array的属性中。

然后输出看看这个属性是否成功赋值。

于是你很开心地按下了command+R,发现这家伙奔溃了,奔溃原因:

[__NSArray0 setName:]: unrecognized selector sent to instance 0x100102f80

NSArray并没有这个setName:这个方法,仔细一看 Xcode 还给我们两个警告。

于是我们进入NSArray+Name.m文件写上 get 方法和 set 方法:

@implementation NSArray (Name)

- (void)setName:(NSString *)name {
    _name = name;
}

- (NSString *)name {
    return _name;
}
@end

很好,两个错误,因为并没有实例变量。或许你觉得可以添加一个扩展。于是你写了一个扩展并且给他添加了一个实例变量NSString *name,然后这次连编译都不通过。

于是你哭了/(ㄒoㄒ)/~~

Category只能给已有的类添加方法,不能添加实例变量

那现在怎么办呢?难道我们之前的问题就解决不了了?

这个时候runtime的作用就体现出来了。之前我们说过,它可以动态的去修改我们创建的结构体(也就已经声明的类)。

利用 Runtime 和 Category 给现有的类添加属性

关联对象

关联对象是只将一个对象a利用一个key绑定一个对象b,之后a就可以利用这个key获取到这个对象b

同时,a可以二次绑定同一个key,并且会替换之前被绑定的对象。之后再通过key获取对象,就是一个新绑定的值了。

是不是感觉和普通的属性很像?可以赋值,可以取值,可以重复赋值然后覆盖。

的确,只是调用一个函数而已。

函数

Runtime 给了我们两个函数来实现关联对象,你只需要#import <objc/runtime.h>就可以使用这两个函数了。

这两个函数分别是:

//set function
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

//get function
id objc_getAssociatedObject(id object, const void *key);

赋值函数

来看看 set 函数里的东西

  • object 要持有“别的对象”的对象,这里也就是指a
  • key 关联关键字,是一个字符串常亮,是一个地址(这里注意,地址必须是不变的,地址不同但是内容相同的也不算同一个key)
  • value 也就是值,你可以猜的出应该是值b
  • policy 这是一个枚举,你可以点进去看看这个枚举是什么:
    • OBJC_ASSOCIATION_ASSIGN
    • OBJC_ASSOCIATION_RETAIN_NONATOMIC
    • OBJC_ASSOCIATION_COPY_NONATOMIC
    • OBJC_ASSOCIATION_RETAIN
    • OBJC_ASSOCIATION_COPY

如果你了解 Objective-C,那你一定知道上面这些枚举的作用了。

所以,我们就可以在前面的NSArray的分类里这么写

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

取值函数

现在来看看 get 函数里的东西

  • object 持有“别的对象”的对象,这里指a
  • key 关联关键字

看完 set 函数之后,get 函数就显而易见了!这里不用多解释,立马就可以写代码

- (NSString *)name {
    return objc_getAssociatedObject(self, "name");
}

验证结果

运行demo,成功输出如下内容:

2016-05-11 09:22:32.950 runtime+Category demo[923:36795] test
Program ended with exit code: 0

说明我们给 array 赋值的结果成功保留下来,下一次去取值可以成功取到上一次保存的值了。

时间: 2024-08-16 17:04:20

Runtime的实践——给一个类添加属性(关联对象)的相关文章

iOS开发大招-使用运行时runtime方法给一个类添加属性

看过一些第三方开源类库的源代码,经常发现他们 给一个 类 添加了一个原本不存在的属性, 比如PPrealSideController 就给 UIViewController添加了一个 self.pprealSideController的属性? 他是如何实现的呢? 1.基本的实现思路 首先我们需要了解,实际上 在我们使用  类似于self.newProperty的语句的时候, 根据点语法的规则实际上是调用的  setNewProperty方法,和  newProperty方法, 那我们可以知道他肯

Objective-C 给分类添加“属性”——关联对象

给分类添加"属性" 咱们知道,分类中可以添加方法,却无法添加属性.那咱们有其他的方法来实现吗? 先来看看下面这段代码: @interface UIView (nl_Frame) @property (nonatomic, assign) CGFloat nl_width; @end @implementation UIView (nl_Frame) - (void)setNl_width:(CGFloat)nl_width { CGRect frame = self.frame; fr

runtime-给系统已有类添加属性

在没有接触runtime之前,我们接触到的能给类进行扩展的方法有类目(category)和延展(extension)两种.类目(category)可以给系统已有类添加扩展方法但是不能添加属性,并且被添加的方法可以被此类的子类所继承:延展(extension)为我们的自定义类添加属性和方法,但是添加的属性和方法都是私有的,在此类的子类中是无法访问的.那么问题来了,如果我们想给系统已有类添加一些方便我们使用的属性要怎么办呢?上述这两种方法中能给系统已有类添加的东西的就只有类目(category)了.

python - 装饰器+描述符(给类添加属性且属性类型审核)

装饰器+描述符 实现给一个类添加属性且对添加的时,对属性进行类型审核: def zsq(**kwargs): def fun(obj): for i,j in kwargs.items(): setattr(obj,i,mxf(i,j)) return obj return fun class mxf(): def __init__(self,na,ty): self.na = na self.ty = ty def __get__(self, instance, owner): return

创建一个Fraction类(分数)实现分数的加减乘除,比较大小、约分等方法。要求:为类添加属性

//在.h文件里 {     NSInteger _numerator;     //分子     NSInteger _denominator;   //分母     }   //属性 @property (nonatomic) NSInteger numerator; @property (nonatomic) NSInteger denominator; //初始化   - (id)initwithNumerator:(NSInteger)numerator denominator:(NS

通过反射把一个类的属性的值赋值给另一个类

两个类我就不创建了,具体实现方法如下: /// <summary> /// 通过反射把一个类的属性的值赋值给另一个类 /// </summary> /// <typeparam name="D"></typeparam> /// <typeparam name="S"></typeparam> /// <param name="s"></param>

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

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

Python笔记(七):字典、类、属性、对象实例、继承

(一)  简单说明 字典是Python的内置数据结构,将数据与键关联(例如:姓名:张三,姓名是键,张三就是数据).例如:下面这个就是一个字典 {'姓名': '张三', '出生日期': '2899-08-12', '成绩': ['3.21', '3.10', '3.01']} 创建字典.添加数据.访问字典数据的方式如下: d = {}  #直接用{}创建字典 f = dict() #通过工厂函数dict()创建字典 #通过下面的方式添加数据 d['姓名'] = '张三' d['出生日期'] = '

scala 第7讲 类的属性和对象的私有字段

温故而知新 之scala第7讲类的属性和对象私有字段百度云盘连接http://yun.baidu.com/share/home?uk=4013289088#category/type=0class Person { private var age = 0 def increment(){age += 1} def current = age } class Student{ private var privateAge = 0 val name = "Scala" def age =