1. 程式人生 > >【OC底層】AssociatedObject 關聯物件

【OC底層】AssociatedObject 關聯物件

如何實現給分類“新增成員變數”?

  • 預設情況下,因為分類底層結構的限制,不能新增成員變數到分類中。但可以通過關聯物件來間接實現
  • 關聯物件提供了以下API

  1> 新增關聯物件

  void objc_setAssociatedObject(id object, const void * key,
  id value, objc_AssociationPolicy policy)

  2> 獲得關聯物件

  id objc_getAssociatedObject(id object, const void * key)

  3> 移除所有的關聯物件

  void objc_removeAssociatedObjects(id object)

 

key的常見用法

 

objc_AssociationPolicy修飾符

 

 

給分類新增屬性例項

假如已經有一個 XGPerson的類,現在我們需要擴充套件這個類,並且新增一個 age 屬性

#import "XGPerson.h"

// 分類屬性是不會生成 get\set 方法的,如果不重寫這兩個方法,就無法正常使用屬性
@interface XGPerson (Test)

@property (nonatomic,assign) int age;

@end
#import "XGPerson+Test.h
" #import <objc/runtime.h> @implementation XGPerson (Test) - (void)setAge:(int)age{ // @selector(age) 這個引數只要傳一個地址指標就可以 objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_ASSIGN); } - (int)age{ // 隱式引數 // _cmd = @selectior(age) return
[objc_getAssociatedObject(self, _cmd) intValue]; }

呼叫:

        XGPerson* p1 = [[XGPerson alloc]init];
        p1.name = @"p1";
        p1.age = 18;
        
        XGPerson* p2 = [[XGPerson alloc]init];
        p2.name = @"p2";
        p2.age = 20;
        
        NSLog(@"p1Name:%@  p1Age:%i----p2Name:%@  p2Age:%i",p1.name,p1.age,p2.name,p2.age);

輸出:

2018-11-29 14:20:38.666084+0800 關聯物件(增加分類屬性)[1923:87124] p1Name:p1  p1Age:18----p2Name:p2  p2Age:20

 

關聯物件的原理

  • 實現關聯物件技術的核心物件有

  AssociationsManager
  AssociationsHashMap
  ObjectAssociationMap
  ObjcAssociation

  •  objc4原始碼解讀:objc-references.mm

   

  • 關聯物件儲存結構圖

  1. 關聯物件並不是儲存在被關聯物件本身記憶體中
  2. 關聯物件儲存在全域性的統一的一個AssociationsManager中
  3. 設定關聯物件為nil,就相當於是移除關聯物件