国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Objc源碼探究(五)category的加載

2019-11-06 09:52:55
字體:
供稿:網(wǎng)友

本文擴(kuò)展自:http://blog.sunnyxx.com/2014/08/30/objc-PRe-main/ 這篇文章主要描述了iOS平臺上main函數(shù)調(diào)用之前所發(fā)生的事。我們從這里開始講述category是如何加載的。

main函數(shù)開始之前,在一些準(zhǔn)備工作之后,libSystem會(huì)調(diào)用

void _objc_init(void)

函數(shù),這里便是runtime的入口,也就是這時(shí)候啟動(dòng)了runtime。蘋果自己的注釋也描述的很清楚

/************************************************************* * _objc_init * Bootstrap initialization. Registers our image notifier with dyld. * Called by libSystem BEFORE library initialization time


蘋果在這個(gè)函數(shù)里面做了一些初始化的工作,包括每個(gè)類+load方法的調(diào)用,關(guān)于load方法的調(diào)用順序如下:

do { // 1. Repeatedly call class +loads until there aren't any more while (loadable_classes_used > 0) { call_class_loads(); } // 2. Call category +loads ONCE more_categories = call_category_loads(); // 3. Run more +loads if there are classes OR more untried categories } while (loadable_classes_used > 0 || more_categories);

接下來蘋果調(diào)用了map_2_images函數(shù),函數(shù)里面在最后又調(diào)用了_read_images函數(shù),該函數(shù)通過_objc_read_categories_from_image實(shí)現(xiàn)category的加載。該函數(shù)的實(shí)現(xiàn)如下:

static bool _objc_read_categories_from_image (header_info * hi){ Module mods; size_t midx; bool needFlush = NO; if (hi->info()->isReplacement()) { // Ignore any categories in this image return NO; } // Major loop - process all modules in the header mods = hi->mod_ptr; // NOTE: The module and category lists are traversed backwards // to preserve the pre-10.4 processing order. Changing the order // would have a small chance of introducing binary compatibility bugs. midx = hi->mod_count; while (midx-- > 0) { unsigned int index; unsigned int total; // Nothing to do for a module without a symbol table if (mods[midx].symtab == nil) continue; // Total entries in symbol table (class entries followed // by category entries) total = mods[midx].symtab->cls_def_cnt + mods[midx].symtab->cat_def_cnt; // Minor loop - register all categories from given module index = total; while (index-- > mods[midx].symtab->cls_def_cnt) { old_category *cat = (old_category *)mods[midx].symtab->defs[index]; needFlush |= _objc_register_category(cat, (int)mods[midx].version); } } return needFlush;}

首先判斷該類是否忽略加載category,如果忽略就直接返回;然后從傳入的hi(其中存儲的是各個(gè)加載的模塊的信息)參數(shù)中遍歷要加載的category的所有模塊;首先判斷模塊的符號表是否為空

// Nothing to do for a module without a symbol table if (mods[midx].symtab == nil) continue;

如果為空就不需要加載了;接下來從該模塊的符號表中取出category的數(shù)量和類的數(shù)量,然后遍歷該模塊所有的category,調(diào)用_objc_register_category函數(shù)進(jìn)行加載。該函數(shù)的實(shí)現(xiàn)如下:

static bool _objc_register_category(old_category *cat, int version){ _objc_unresolved_category * new_cat; _objc_unresolved_category * old; Class theClass; // If the category's class exists, attach the category. if ((theClass = objc_lookUpClass(cat->class_name))) { return _objc_add_category_flush_caches(theClass, cat, version); } // If the category's class exists but is unconnected, // then attach the category to the class but don't bother // flushing any method caches (because they must be empty). // YES unconnected, NO class_handler if ((theClass = look_up_class(cat->class_name, YES, NO))) { _objc_add_category(theClass, cat, version); return NO; } // Category's class does not exist yet. // Save the category for later attachment. if (PrintConnecting) { _objc_inform("CONNECT: pending category '%s (%s)'", cat->class_name, cat->category_name); } // Create category lookup table if needed if (!category_hash) category_hash = NXCreateMapTable(NXStrValueMapPrototype, 128); // Locate an existing list of categories, if any, for the class. old = (_objc_unresolved_category *) NXMapGet (category_hash, cat->class_name); // Register the category to be fixed up later. // The category list is built backwards, and is reversed again // by resolve_categories_for_class(). new_cat = (_objc_unresolved_category *) malloc(sizeof(_objc_unresolved_category)); new_cat->next = old; new_cat->cat = cat; new_cat->version = version; (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat); return NO;}

蘋果對該函數(shù)也進(jìn)行了說明:

/************************************************************************ _objc_register_category.* Process a category read from an image. * If the category's class exists, attach the category immediately. * Classes that need cache flushing are marked but not flushed.* If the category's class does not exist yet, pend the category for * later attachment. Pending categories are attached in the order * they were discovered.* Returns YES if some method caches now need to be flushed.**********************************************************************/

如果category對應(yīng)的類存在,那么就立即加載category;如果對應(yīng)的類不存在,那么將category掛起等待后續(xù)加載;如果類的一些方法緩存需要刷新,但是刷新行為不在該函數(shù)中完成,該函數(shù)返回YES。 _objc_register_category函數(shù)首先去尋找category對應(yīng)的類

// If the category's class exists, attach the category. if ((theClass = objc_lookUpClass(cat->class_name))) { return _objc_add_category_flush_caches(theClass, cat, version); } // If the category's class exists but is unconnected, // then attach the category to the class but don't bother // flushing any method caches (because they must be empty). // YES unconnected, NO class_handler if ((theClass = look_up_class(cat->class_name, YES, NO))) { _objc_add_category(theClass, cat, version); return NO; }

如果找到了,就加載category到對應(yīng)的類,如果沒找到,就建立一個(gè)hash表,將這個(gè)category存起來,待之后系統(tǒng)去加載。 category的加載通過_objc_add_category_flush_caches函數(shù)實(shí)現(xiàn):

/************************************************************************ _objc_add_category_flush_caches. Install the specified category's * methods into the class it augments, and flush the class' method cache.* Return YES if some method caches now need to be flushed.**********************************************************************/static bool _objc_add_category_flush_caches(Class cls, old_category *category, int version){ bool needFlush = NO; // Install the category's methods into its intended class { mutex_locker_t lock(methodListLock); _objc_add_category (cls, category, version); } // Queue for cache flushing so category's methods can get called if (category->instance_methods) { cls->setInfo(CLS_FLUSH_CACHE); needFlush = YES; } if (category->class_methods) { cls->ISA()->setInfo(CLS_FLUSH_CACHE); needFlush = YES; } return needFlush;}

這里面主要就是調(diào)用_objc_add_category函數(shù),該函數(shù)的實(shí)現(xiàn)如下:

/************************************************************************ _objc_add_category. Install the specified category's methods and* protocols into the class it augments.* The class is assumed not to be in use yet: no locks are taken and * no method caches are flushed.**********************************************************************/static inline void _objc_add_category(Class cls, old_category *category, int version){ if (PrintConnecting) { _objc_inform("CONNECT: attaching category '%s (%s)'", cls->name, category->category_name); } // Augment instance methods if (category->instance_methods) _objc_insertMethods (cls, category->instance_methods, category); // Augment class methods if (category->class_methods) _objc_insertMethods (cls->ISA(), category->class_methods, category); // Augment protocols if ((version >= 5) && category->protocols) { if (cls->ISA()->version >= 5) { category->protocols->next = cls->protocols; cls->protocols = category->protocols; cls->ISA()->protocols = category->protocols; } else { _objc_inform ("unable to add protocols from category %s.../n", category->category_name); _objc_inform ("class `%s' must be recompiled/n", category->class_name); } } // Augment instance properties if (version >= 7 && category->instance_properties) { if (cls->ISA()->version >= 6) { _class_addProperties(cls, category->instance_properties); } else { _objc_inform ("unable to add instance properties from category %s.../n", category->category_name); _objc_inform ("class `%s' must be recompiled/n", category->class_name); } } // Augment class properties if (version >= 7 && category->hasClassPropertiesField() && category->class_properties) { if (cls->ISA()->version >= 6) { _class_addProperties(cls->ISA(), category->class_properties); } else { _objc_inform ("unable to add class properties from category %s.../n", category->category_name); _objc_inform ("class `%s' must be recompiled/n", category->class_name); } }}

這里主要是做了三件事: 1、將category的實(shí)例方法和類方法添加到類中 2、將category的protocol添加到類中 3、將category的實(shí)例對象和類對象添加到類中

至此,runtime幫助我們完成了所有的category的加載。

最后附上category的結(jié)構(gòu),其實(shí)也十分簡單:

struct old_category { char *category_name; char *class_name; struct old_method_list *instance_methods; struct old_method_list *class_methods; struct old_protocol_list *protocols; // Fields below this point are in version 7 or later only. uint32_t size; struct old_property_list *instance_properties; // Check size for fields below this point. struct old_property_list *class_properties; bool hasClassPropertiesField() const { return size >= offsetof(old_category, class_properties) + sizeof(class_properties); }};
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 泾源县| 沁阳市| 金阳县| 英吉沙县| 永济市| 龙岩市| 疏附县| 盱眙县| 天镇县| 江川县| 当雄县| 原阳县| 房产| 舞阳县| 芷江| 秭归县| 玉树县| 栾川县| 长沙市| 徐水县| 缙云县| 大理市| 洛扎县| 定兴县| 双江| 宁蒗| 滦平县| 叙永县| 乐平市| 乌拉特中旗| 普定县| 东方市| 广德县| 鄂尔多斯市| 香格里拉县| 华安县| 营山县| 富源县| 吉木萨尔县| 罗甸县| 蓬安县|