分類-Category
1 簡介
- 主要為類新增方法:不管系統的類還是自定義的類
- 宣告私有方法(擴充套件)
- 分類是執行期決議的;擴充套件是編譯期決議,需要原始碼才能在主類新增擴充套件;所以系統類是無法新增擴充套件
- 分類的結構體,沒有成員變數(ivar)列表,所以無法新增成員變數
typedef struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
} category_t;
2 Category如何載入
- 把Category的例項方法,協議以及屬性新增到主類
- 把Category的類方法和協議新增到類的metaClass
新增方法的策略:
是將Category和主類的方法拼接起來,放到方法列表飯(陣列):先載入主類的方法,載入分類方法時,是先把分類方法放到新陣列,再把主類的方法放到新陣列後
而查詢方法也是按照順序查詢,所以會有Category覆蓋主類方法的說法
for (uint32_t m = 0;
(scanForCustomRR || scanForCustomAWZ) && m < mlist->count;
m++)
{
SEL sel = method_list_nth(mlist, m)->name;
if (scanForCustomRR && isRRSelector(sel)) {
cls->setHasCustomRR();
scanForCustomRR = false;
} else if (scanForCustomAWZ && isAWZSelector(sel)) {
cls->setHasCustomAWZ();
scanForCustomAWZ = false;
}
}
// Fill method list array
newLists[newCount++] = mlist;
.
.
.
// Copy old methods to the method list array
for (i = 0; i < oldCount; i++) {
newLists[newCount++] = oldLists[i];
}
3 +load的載入順序
先呼叫主類的load方法,再呼叫Category;Category之間的順序由編譯順序決定
4 關聯物件(AssociatedObject)
#import "MyClass.h"
@interface MyClass (Category1)
@property(nonatomic,copy) NSString *name;
@end
#import "MyClass+Category1.h"
#import <objc/runtime.h>
@implementation MyClass (Category1)
+ (void)load
{
NSLog(@"%@",@"load in Category1");
}
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self,
"name",
name,
OBJC_ASSOCIATION_COPY);
}
- (NSString*)name
{
NSString *nameObject = objc_getAssociatedObject(self, "name");
return nameObject;
}
@end
所有的關聯物件都由AssociationsManager管理,通過Hash表管理,key是物件地址,value是Hash表,這個Hash表則儲存了所有的KV對。AssociationsManager定義如下:
class AssociationsManager {
static OSSpinLock _lock;
static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap.
public:
AssociationsManager() { OSSpinLockLock(&_lock); }
~AssociationsManager() { OSSpinLockUnlock(&_lock); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}
};
AssociationsManager裡面是由一個靜態AssociationsHashMap來儲存所有的關聯物件的。這相當於把所有物件的關聯物件都存在一個全域性map裡面。而map的的key是這個物件的指標地址(任意兩個不同物件的指標地址一定是不同的),而這個map的value又是另外一個AssociationsHashMap,裡面儲存了關聯物件的kv對。而在物件的銷燬邏輯裡面,見objc-runtime-new.mm:
void *objc_destructInstance(id obj)
{
if (obj) {
Class isa_gen = _object_getClass(obj);
class_t *isa = newcls(isa_gen);
// Read all of the flags at once for performance.
bool cxx = hasCxxStructors(isa);
bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
if (!UseGC) objc_clear_deallocating(obj);
}
return obj;
}
嗯,runtime的銷燬物件函式objc_destructInstance裡面會判斷這個物件有沒有關聯物件,如果有,會呼叫_object_remove_assocations做關聯物件的清理工作。
參考文章
相關文章
- Runtime原始碼 Category(分類)原始碼Go
- Object C學習筆記14-分類(category)Object筆記Go
- iOS分類(category)、類擴充套件(extension)、繼承的區別iOSGo套件繼承
- PropertyGrid控制元件 分類(Category)及屬性(Property)排序控制元件Go排序
- [文件教程][通用]模板中直接獲取對應分類的任意級別子分類資料:get_children_by_categoryGo
- [文件教程][通用]模板中直接獲取任意分類URL連結或其他分類相關欄位資訊:get_info_by_categoryGo
- Objective-C 類別(category)和擴充套件(Extension)ObjectGo套件
- Category探索Go
- Extension,CategoryGo
- hello categoryGo
- man categoryGo
- 京東獲得jd商品分類API介面(父分類、根分類、子分類)API
- SAP SD 基礎知識之行專案類別(Item Category)Go
- wordpress 獲取分類ID,分類標題,分類描述,分類連結url函式函式
- Category – 簡介Go
- OC Category、AssociatedObjectGoObject
- 分類 和 聚類聚類
- ML.NET 示例:多類分類之問題分類
- ML.NET 示例:多類分類之鳶尾花分類
- TopThink小組欄目中的各個小組是OT中的分類Category還是型別為“目錄”的文件?Go型別
- SQL分類SQL
- 模式分類模式
- Nosql分類SQL
- 分類器
- 分類2
- [譯]Functor 與 Category (軟體編寫)(第六部分)Go
- IOS category 與 extensioniOSGo
- Category_theory and FunctorGo
- Wait Events的分類及分類依據AI
- SAP SD 基礎知識之計劃行類別(Schedule Line Category)Go
- IP地址分類(A類 B類 C類 D類 E類)
- 概率分類之樸素貝葉斯分類(垃圾郵件分類python實現)Python
- 如何在SAP Spartacus category 頁面裡拿到當前的category資訊Go
- Category的本質<一>Go
- iOS底層原理-CategoryiOSGo
- Category的實現原理Go
- 談談Category和ExtensionGo
- iOS設計模式——CategoryiOS設計模式Go