Objective-C——關聯對象

動態語言函數

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了。

相關文章
相關標籤/搜索