给分类添加“属性”
咱们知道,分类中可以添加方法,却无法添加属性。那咱们有其他的方法来实现吗?
先来看看下面这段代码:
@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_width
、setNl_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;
很爽吧!以后就可以给已有类添加“属性”了。这可是一个很强大的功能哟,如果你查看过一些强大的第三方库的话,就会发现,这是一个常用的技巧。
为什么分类无法添加属性
待写
关联对象的基本原理
待写