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;
  frame.size.width = nl_width;
  self.frame = frame;
}

- (CGFloat)nl_width {
  return CGRectGetWidth(self.frame);
}
@end

在这里给 UIView增加了一个宽度“属性”:nl_width,而且为其实现了相应的 getter和 setter方法(nl_widthsetNl_width:)。这两个方法实际上访问的 frame“属性”,为什么给在这里也打上双引号?没错,frame也是定义在分类里边的:

@interface UIView(UIViewGeometry)
@property(nonatomic) CGRect            frame;
//...
@end

可以看到,这种定义在分类里的“属性”,实际上是实现了相应的方法,并在方法里边通过访问其它属性来达到目的。这通常用来简化某些操作,比如定义咱们这个分类后,获取视图的宽度只要view.nl_width就可以了,再不用CGRectGetWidth(view.frame)来得到宽度,而且可读性也增强了很多。

再来看看这个需求:在 sqlite中,第一个表如果在没有指定主键的情况下,那默认就会定义一个主键rowid。咱们就把这个 rowid直接放到 NSObject里边,作为属性,那么任何对象也会有这个主键rowid了。但是这个rowid却无法像上边的nl_width一样通过访问其它属性来达到目的。那该怎么办?

关联对象

本节的主角出场了:关联对象

在使用关联对象之前,得先引入头文件:

#import <objc/runtime.h>

可以在该头文件中找到三个允许你将任何键值在运行时关联到对象上的函数:

objc_setAssociatedObject       // 设置关联对象
objc_getAssociatedObject       // 获取关联对象
objc_removeAssociatedObjects   // 移除关联对象

既然有了这个工具,那么咱们再来看看:

@interface NSObject (nl_sqlite)
@property (nonatomic, assign) NSUInteger rowid;
@end
@implementation NSObject (nl_sqlite)
static void *nl_sqlite_rowid_key = &nl_sqlite_rowid_key;
- (void)setRowid:(NSUInteger)rowid {
  objc_setAssociatedObject(self, nl_sqlite_rowid_key, @(rowid), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSUInteger)rowid {
  return [objc_getAssociatedObject(self, nl_sqlite_rowid_key) unsignedLongValue];
}
@end

上面的代码,就是通过关联对象给NSObject增加了一个rowid“属性”。关联对象在使用时,需要咱们提供一个指针,即key,用来识别被关联的对象。咱们这里的key就是一个空指针:nl_sqlite_rowid_key。当然,你也可以@selector(rowid)来作为 key(常用)。

于是,就可以这么来用了:

id person = [NSObject new];
person.rowid = 1;

很爽吧!以后就可以给已有类添加“属性”了。这可是一个很强大的功能哟,如果你查看过一些强大的第三方库的话,就会发现,这是一个常用的技巧。

为什么分类无法添加属性

待写

关联对象的基本原理

待写

时间: 2024-10-06 00:07:37

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

OC对象给分类添加属性

OC对象中不能给分类添加属性,但是在实际开发中,经常为了更好的性能需要给分类添加属性,那么 添加的属性不能有默认的成员变量,需要我们自己实现set和get方法,要用到运行时 如下: #import <objc/runtime.h> //运行时的关联对象,动态添加属性 const void *URLStringKey = "URLStringKey"; //set方法 - (void)setUrlStr:(NSString *)urlStr { objc_setAssocia

快速上手Runtime(二)之给分类添加属性

我们都知道,分类是不能直接添加属性的,那么我们有时候又需要实现这个功能,那么我们应该怎么办才能为分类添加上属性呢. Runtime给分类添加属性原理 给一个类声明属性,其实本质就是给这个类添加关联,并不是直接把这个值的内存空间添加到类存空间. Runtime给分类添加属性步骤 1.在分类的.h文件中声明想要定义的属性 2.在分类的.m文件中实现getter和setter方法 3.引入runtime头文件,然后在setter方法中用objc_setAssociatedObject关联对象 比如给N

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

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

分类添加属性之关联引用

分类是不能合成属性的,因为合成属性会生成对应的实例变量,而分类是不允许添加实例变量的(实例变量所在内存区域已初始化为不可更改,无法在动态运行时修改之). 虽然不能增加实例变量,但是添加属性还是可以的,只不过需要自己在分类中实现get和set方法,同时标记属性为动态获取. 其中一种方法叫做关联引用,实现了用存取器来访问属性,当然实际上并没有实例变量,所以本质上只不过是增加了两个方法而已. 首先在.h中声明属性: #import <UIKit/UIKit.h> @interface UIViewC

利用runtime给分类添加属性

在分类中利用@property添加属性,只能声明实例变量的存取声明,而没有存取方法的实现,可以利用runtime实现. 在头文件中定义属性 @property (nonatomic, copy)NSString *name; 在.m文件中实现存取方法 static char *key = "name"; - (NSString *)name { // 根据关联的key,获取关联的值. return objc_getAssociatedObject(self, key); } - (vo

通过运行时动态给分类添加属性

#import <UIKit/UIKit.h> /** iOS 开发中,分类默认不允许保存属性 如果在分类中,定义一个属性,需要自己实现 getter & setter 方法,而且没有 _成员变量 如果在自己开发的框架中,希望在分类中动态添加属性,可以通过 OC 运行时的关联对象的功能! 运行时非常重要的一个应用:给分类动态添加属性,结果能够让框架包装的更好,让使用者做出最小的修改! */ @interface UIImageView (WebImage) @property (non

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

相关文章: <Runtime的初步认识--结构体与类> <Runtime的初步认识--消息机制> 一提到给一个类添加点什么,我们有可能首先就想到类别(Category).那么我们就弄一下. 利用 Category 给现有的类添加属性 比如我们要给一个 NSArray 添加一个属性叫做NSString *name. 我们首先新建一个Objective-C文件. File: Name File Type:Category Class:NSArray 然后我们在NSArray+Name.

给分类(Category)添加属性

遇到一个问题,写了一个分类,但原先类的属性不够用.添加一个属性,调用的时候崩溃了,说是找不到getter.setter方法.查了下文档发现,OC的分类允许给分类添加属性,但不会自动生成getter.setter方法.有没有解决方案呢?有,通过运行时建立关联引用.接下来以添加一个这样的属性为例: @property (nonatomic, copy) NSString *str; 1.引入运行时头文件. #import <objc/runtime.h> 2.在匿名分类或者头文件中添加属性.区别是

运行时之关联对象

头文件: #import <objc/runtime.h> Objective-C 开发者习惯于警惕运行时的东西,理由是运行时改变了运行在它上面代码的实际结构. 另一方面,<objc/runtime.h> 的功能就是为应用或框架增加更强大的新特性,是其他的方式无法 实现的.同时它也可能破坏原来代码的逻辑结构,一切与之可能进行的交互,都将有可怕的副作用. 给我们带来极大的惶恐,因此,我们称之为浮士德,也是NSHipster读者经常被所要求的科目之一: 关联的对象.关联的对象或关联的引