經常使用的底層語法(objc_get,class_get,_cmd,objc_msgSend)

一,關聯 objc_get函數

1)創建關聯:objc_setAssociatedObject;該函數須要四個參數:源對象,關鍵字,關聯的對象和一個關聯策略;當源對象銷燬,關聯的對象也會被銷燬測試

源對象: 即綁定者this

關鍵字: 是一個void類型的指針。每個關聯的關鍵字必須是惟一的。一般都是會採用靜態變量來做爲關鍵字spa

關聯的對象: 綁定到源對象身上的對象指針

關聯策略: 代表了相關的對象是經過賦值,保留引用仍是複製的方式進行關聯的;還有這種關聯是原子的仍是非原子的。這裏的關聯策略和聲明屬性時的很相似。這種關聯策略是經過使用預先定義好的常量來表示的。OBJC_ASSOCIATION_ASSIGN、OBJC_ASSOCIATION_RETAIN_NONATOMIC、OBJC_ASSOCIATION_COPY_NONATOMIC等對象

2)獲取相關聯對象:objc_getAssociatedObject:該函數須要兩個參數:源對象,關鍵字ci

3)斷開關聯:斷開關聯是使用objc_setAssociatedObject函數,傳入關聯的對象爲nil值便可。rem

使用函數objc_removeAssociatedObjects能夠斷開全部關聯。一般狀況下不建議使用這個函數,由於他會斷開全部關聯。只有在須要把對象恢復到「原始狀態」的時候纔會使用這個函數。get

 

例子:cmd

static char objKey; 

NSArray * array =[[NSArray alloc] initWidthObjects:@"One", @"Two", @"Three", nil];

objc_setAssociatedObject(array, &objKey, @「對象」, OBJC_ASSOCIATION_RETAIN);

NSString * associatedObject = (NSString *)objc_getAssociatedObject(array, &objKey);  

 

二,class_get

1)得到實例方法: Method m1 = class_getInstanceMethod([對象 class], @selector(對象方法));

2)得到類方法: Method m2 = class_getClassMethod([類 class], @selector(類方法)); 

3)方法互調: method_exchangeImplementations(m1, m2); 即執行方法m1變成執行是m2,執行方法m2變成執行是m1

 例子:

  1.     Person * p1 = [[Person alloc] init];  
  2.     Method m1 = class_getInstanceMethod([p1 class], @selector(對象方法));  
  3.     Method m2 = class_getClassMethod([Person class], @selector(類方法));  
  4.     NSLog(@"測試前:");  
  5.     [p1 對象方法];  
  6.     [Person 類方法];  
  7.     method_exchangeImplementations(m1, m2);  
  8.     NSLog(@"測試後:");  
  9.     [p1 對象方法];  
  10.     [Person 類方法]; 

輸出:

  1. 2015-11-04 13:37:08.539 02-runtime[2776:69899] 測試前:  
  2. 2015-11-04 13:37:08.539 02-runtime[2776:69899] this is a 對象方法 method  
  3. 2015-11-04 13:37:08.539 02-runtime[2776:69899] this is a 類方法 method  
  4. 2015-11-04 13:37:08.540 02-runtime[2776:69899] 測試後:  
  5. 2015-11-04 13:37:08.540 02-runtime[2776:69899] this is a 類方法 method  
  6. 2015-11-04 13:37:08.540 02-runtime[2776:69899] this is a 對象方法 method 

 

三,_cmd的用法

_cmd在Objective-C的方法中表示當前方法的selector,正如同self表示當前方法調用的對象實例。NSStringFromSelector(_cmd)獲得是方法的名稱

例如

static char kExtendVarKey; // 鍵名

- (void)someCategoryMethod

{

    NSString *extendVar = objc_getAssociatedObject(self, &kExtendVarKey);

    if(!extendVar){

        extendVar = @"someText";

        objc_setAssociatedObject(self, &kExtendVarKey, extendVar, OBJC_ASSOCIATION_COPY_NONATOMIC);

    }

}

 

等同於下面代碼

- (void)someCategoryMethod

{

    NSString *extendVar = objc_getAssociatedObject(self, _cmd);

    if(!extendVar){

        extendVar = @"someText";

        objc_setAssociatedObject(self, _cmd, extendVar, OBJC_ASSOCIATION_COPY_NONATOMIC);

    }

}

 

四,objc_msgSend:該函數至少有兩個參數:objc_msgSend(消息的接受者, selector, param1, param2, …);

1)概念:其實每一個類中都有一張方法列表去存儲這個類中有的方法,當發出objc_msgSend方法時候,就會順着列表去找這個方法是否存在,若是不存在,則向該類的父類繼續查找,直到找到位置。若是始終沒有找到方法,那麼就會進入到消息轉發機制;objc_msgSend被分爲2個過程:1)在cache中尋找SEL。2)在MethodTable尋找SEL。

例子

id returnValue = [someObject messageName:parameter]; ======》 id returnValue = objc_msgSend(someObject,@selector(messageName),paramter)

Id returnValue = [super messageName:parameter]; ======》 id returnValue = objc_msgSendSuper(someObject,@selector(messageName),paramter)

相關文章
相關標籤/搜索