動態語言函數
OC是一種動態語言,它的方法,對象的類型都是到運行的時候纔可以肯定的。因此這就使得OC存在了關聯對象這一強大的機制。atom
關聯對象spa
所謂關聯對象,其實就是咱們在運行時對一個已存在的對象上面綁定一個對象,使兩個對象變成動態的聚合關係。指針
關聯對象和屬性同樣有着關鍵字,如下是關聯對象的存儲策略:code
關聯類型 | 等效的@property屬性 |
OBJC_ASSOCIATION_ASSIGN | assign |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | nonatomic,retain |
OBJC_ASSOCIATION_COPY_NONATOMIC | nonatomic,copy |
OBJC_ASSOCIATION_RETAIN | retain |
OBJC_ASSOCIATION_COPY | copy |
關聯對象主要靠下面三個函數,它們都位於<objc/runtime>下對象
void objc_setAssociatedObject(id object, void *key ,id value ,objc_AssociationPolicy policy)blog
設置關聯對象內存
參數 | 說明 |
object | 要進行關聯的對象 |
key | 一個內存表示,在比較兩個關聯對象是否相等時,比較的就是內存地址,因此通常用一個全局靜態變量表示 |
value | 被關聯的對象 |
policy | 存儲策略 |
id objc_getAssociatedObject(id object, void *key)ci
獲取關聯對象rem
void objc_removeAssociatedObjects(id object)
刪除關聯對象
做用
關聯對象通常用於動態的擴展一個對象,可是這通常都是在其餘方法不行的過後纔會使用,由於關聯對象極可能會出現難以查找的bug。
關聯對象有時也會用於在category向類添加屬性,這點等會兒在分析。
下面Demo在UIAlertView上面動態綁定了一個block,把按鈕處理邏輯和alert調用整合在了一塊兒。
static char *AlertKey = "alertKey"; - (void)viewDidLoad { [super viewDidLoad]; alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil]; } - (IBAction)click:(id)sender { void (^block) (NSInteger) = ^(NSInteger buttonIndex){ if (buttonIndex == 0){ NSLog(@"click cancel"); } else{ NSLog(@"click other"); } }; objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY); [alert show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey); block(buttonIndex); }
運行程序點擊兩個按鈕分別輸出以下
2015-08-11 22:51:27.146 Dynamic[4592:2833778] click other 2015-08-11 22:51:28.262 Dynamic[4592:2833778] click cancel
接下來咱們給UIViewController在category中添加一個addition屬性
#import "ViewController.h" #import <objc/runtime.h> @interface UIViewController (Addition) @property(nonatomic ,copy) NSString *addition; @end
#import "UIViewController+Addition.h" static const void *IndieBandNameKey = &IndieBandNameKey; @implementation UIViewController (Addition) -(void)setAddition:(NSString *)addition{ objc_setAssociatedObject(self, IndieBandNameKey, addition, OBJC_ASSOCIATION_COPY); } -(NSString *)addition{ return objc_getAssociatedObject(self, IndieBandNameKey); } @end
這裏說明一下,這裏關聯的其實是形參addition,和屬性沒有什麼關係,寫@property 就是爲了可以使用‘.’語法。可是@porperty裏面的屬性存儲策略仍是要和關聯對象一致的,這樣不容易形成誤解。
因此每次setAddition實際上咱們並非修改了原有內存的值,而是改變了指針指向的地址,這裏須要注意一下。
而後修改剛纔alert的代碼
- (void)viewDidLoad { [super viewDidLoad]; alert = [[UIAlertView alloc] initWithTitle:@"alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil]; alert.delegate = self; self.addition = @"addition"; } - (IBAction)click:(id)sender { void (^block) (NSInteger) = ^(NSInteger buttonIndex){ if (buttonIndex == 0){ NSLog(@"click cancel"); objc_removeAssociatedObjects(self); } else{ NSLog(@"click other"); NSLog(@"%@",self.addition); } }; objc_setAssociatedObject(alert, AlertKey, block, OBJC_ASSOCIATION_COPY); [alert show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { void (^block)(NSInteger) = objc_getAssociatedObject(alertView, AlertKey); block(buttonIndex); }
注意三條加粗的語句,而後咱們運行看結果
2015-08-11 22:53:54.353 Dynamic[4655:2849502] click other 2015-08-11 22:53:54.353 Dynamic[4655:2849502] addition 2015-08-11 22:53:55.804 Dynamic[4655:2849502] click cancel 2015-08-11 22:53:57.491 Dynamic[4655:2849502] click other 2015-08-11 22:53:57.491 Dynamic[4655:2849502] (null)
首先咱們使用了關聯對象,因此點擊other的時候會看到打印出了addition。點擊cancel的時候又由於咱們remove了關聯對象,此時再點擊other的時候addition就變成null了。