在使用OC開發中,咱們常常使用分類爲一些不方便修改的類,添加分類,達到爲類添加"屬性"和方法的目的,下面是爲LBPerson類添加分類的代碼:數組
#import "LBPerson.h" NS_ASSUME_NONNULL_BEGIN @interface LBPerson (Animation) - (void)run; @end NS_ASSUME_NONNULL_END #import "LBPerson+Animation.h" @implementation LBPerson (Animation) - (void)run { NSLog(@"LBPerson+Animation.h"); } @end
LBPerson中代碼以下:源碼分析
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface LBPerson : NSObject - (void)run; @end NS_ASSUME_NONNULL_END
#import "LBPerson.h" @implementation LBPerson - (void)run { NSLog(@"LBPerson run"); } @end
LBPerson+Animation中代碼以下:ui
#import "LBPerson.h" NS_ASSUME_NONNULL_BEGIN @interface LBPerson (Animation) - (void)run; @end NS_ASSUME_NONNULL_END
#import "LBPerson+Animation.h" @implementation LBPerson (Animation) - (void)run { NSLog(@"Animation run"); } @end
在main方法中調用person對象的run方法代碼以及打印以下:spa
int main(int argc, const char * argv[]) { @autoreleasepool { LBPerson *person = [[LBPerson alloc] init]; [person run]; } return 0; } // 輸出結果 Animation run
下面就從runtime的源碼分析爲何會按照上述規則進行調用:code
// cls 本類 // cats_list 存儲分類數組 // cats_count 存儲分類的數量 static void attachCategories(Class cls, const locstamped_category_t *cats_list, uint32_t cats_count, int flags) { if (slowpath(PrintReplacedMethods)) { printReplacements(cls, cats_list, cats_count); } if (slowpath(PrintConnecting)) { _objc_inform("CLASS: attaching %d categories to%s class '%s'%s", cats_count, (flags & ATTACH_EXISTING) ? " existing" : "", cls->nameForLogging(), (flags & ATTACH_METACLASS) ? " (meta)" : ""); } /* * Only a few classes have more than 64 categories during launch. 在啓動期間只有少數類擁有超過64個分類 * This uses a little stack, and avoids malloc. * 使用少許棧避免分類 * Categories must be added in the proper order, which is back 分類確定會按照合適的順序被添加,這個順序就是從後向前 * to front. To do that with the chunking, we iterate cats_list 爲了作這個組塊,咱們迭代分類數組從前到後 * from front to back, build up the local buffers backwards, 建造一個向後的本地緩衝 * and call attachLists on the chunks. attachLists prepends the 調用附加數組在多個組塊上 * lists, so the final result is in the expected order. 附加數組頻道list上,因此最終的結果就是按照期待的順序 */ constexpr uint32_t ATTACH_BUFSIZ = 64; method_list_t *mlists[ATTACH_BUFSIZ]; // 類方法數組 property_list_t *proplists[ATTACH_BUFSIZ]; // 對象方法數組 protocol_list_t *protolists[ATTACH_BUFSIZ]; //協議數組 uint32_t mcount = 0; uint32_t propcount = 0; uint32_t protocount = 0; bool fromBundle = NO; bool isMeta = (flags & ATTACH_METACLASS); // 是不是元類 auto rwe = cls->data()->extAllocIfNeeded(); // 找到本類的rw 而且判斷是否須要額外分配 // 遍歷分類數組 for (uint32_t i = 0; i < cats_count; i++) { auto& entry = cats_list[i]; // 具體的分類 // 取出類方法 method_list_t *mlist = entry.cat->methodsForMeta(isMeta); if (mlist) { if (mcount == ATTACH_BUFSIZ) { prepareMethodLists(cls, mlists, mcount, NO, fromBundle); // 添加到原本的方法列表中 rwe->methods.attachLists(mlists, mcount); mcount = 0; } mlists[ATTACH_BUFSIZ - ++mcount] = mlist; fromBundle |= entry.hi->isBundle(); } // 取出對象方法 property_list_t *proplist = entry.cat->propertiesForMeta(isMeta, entry.hi); if (proplist) { if (propcount == ATTACH_BUFSIZ) { rwe->properties.attachLists(proplists, propcount); propcount = 0; } proplists[ATTACH_BUFSIZ - ++propcount] = proplist; } // 取出協議 protocol_list_t *protolist = entry.cat->protocolsForMeta(isMeta); if (protolist) { if (protocount == ATTACH_BUFSIZ) { rwe->protocols.attachLists(protolists, protocount); protocount = 0; } protolists[ATTACH_BUFSIZ - ++protocount] = protolist; } } if (mcount > 0) { prepareMethodLists(cls, mlists + ATTACH_BUFSIZ - mcount, mcount, NO, fromBundle); rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount); if (flags & ATTACH_EXISTING) flushCaches(cls); } rwe->properties.attachLists(proplists + ATTACH_BUFSIZ - propcount, propcount); rwe->protocols.attachLists(protolists + ATTACH_BUFSIZ - protocount, protocount); }
決定方法調用順序就是下面源碼:orm
void attachLists(List* const * addedLists, uint32_t addedCount) { if (addedCount == 0) return; if (hasArray()) { // many lists -> many lists // 舊的數組大小 uint32_t oldCount = array()->count; uint32_t newCount = oldCount + addedCount; // 須要從新分配的大小 setArray((array_t *)realloc(array(), array_t::byteSize(newCount))); array()->count = newCount; // 至關於把原來的數據日後面移動 memmove(array()->lists + addedCount, array()->lists, oldCount * sizeof(array()->lists[0])); // 把新添加的數據放到最前面以前舊數據放的位置 memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0])); } else if (!list && addedCount == 1) { // 0 lists -> 1 list list = addedLists[0]; } else { // 1 list -> many lists List* oldList = list; uint32_t oldCount = oldList ? 1 : 0; uint32_t newCount = oldCount + addedCount; setArray((array_t *)malloc(array_t::byteSize(newCount))); array()->count = newCount; if (oldList) array()->lists[addedCount] = oldList; memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0])); } }
上述源碼註釋純屬我的的理解對象