標籤:關聯對象
給分類添加“屬性”
咱們知道,分類中可以添加方法,卻無法添加屬性。那咱們有其他的方法來實現嗎?
先來看看下面這段代碼:
@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
就是一個null 指標:nl_sqlite_rowid_key
。當然,你也可以@selector(rowid)
來作為 key
(常用)。
於是,就可以這麼來用了:
id person = [NSObject new];person.rowid = 1;
很爽吧!以後就可以給已有類添加“屬性”了。這可是一個很強大的功能喲,如果你查看過一些強大的第三方庫的話,就會發現,這是一個常用的技巧。
為什麼分類無法添加屬性
待寫
關聯對象的基本原理
待寫
Objective-C 給分類添加“屬性”——關聯對象