iOS底层-类的加载(中)

上一篇咱们根究到了readClass函数,仅仅对函数姓名进行了赋值,并没有对rorw进行操作,本篇咱们就持续根究_read_images函数剩余的调用。

realizeClass的引入

由于咱们根究的目的是的加载,变量的界说咱们先疏忽protocolcat实例化数组egorieappointments的当地。为了调试代码,咱们首先仍是先创立一个JSPerson类:

@interface JSPerson : NSObject
@property (nonatomic, strong) NSString *nickName;
​
- (vo实例化一个类id)say1;
- (void)say2;
​
+ (void)sayHappy;
@end
​
#import "JSPerson.h"
@源码编辑器implementation JSPe实例化类rson
​
- (void)实例化目标是什么意思say1{
 NSLog(@"JSPerson say : %s",变量是什么意思__func__);
}
- (void)say2{
 NSLog(@"JSPerson say : %s",__func__);
}
​
+ (void)load{
 NSLog(@"load");
}
+ (void)sayHappy{
 NSLog(@"JSPerson say : %s"实例化目标是什么意思,__func__);
}
@end

接下来咱们持续看_read_images函数,发现和类相关的当地有两个当地,realize non-lazy classesrealize futureSwift classes,咱们在swift代码是什么意思两段代码中参加咱们调试的代码,为了调查咱们自界说类的加载情况:

  // R实例化servlet类异常ealize non-lazy classes (for +load methods and static instances)
 for (EACH_HEADER) {
   cswiftcode代码查询lassref_t const *classlist = hi->nlclslist(&count);
   for (i = 0; i < count; i++) {
     Class cls = remapClass(classlist[i]);
     if (!clapproachs) continue;
     ///调试代码 确定是咱们自界说的类
     const char *mangledName = cls->nonlaz源码本钱yMan实例化一个类gledName();
     const char *customerClassName = "JSPerson";
     if (strcmp(mangled实例化目标是什么意思Name, customerClassName) == 0) {
       //打印类名
       printf("%s -: no源码下载n-laz源码是什么意思y classes要研讨的类: - %sn",__func_变量是什么意思_,mangledName);
      }
​
     addClassTableEntry(cls);
​
     if (cls->isSwiftStable()变量名的命名规矩) {
       if源码 (cls->swiftMetadataInitializer()) {
         _objc_fatal("Swift class %s with a metadata init源码年代ializer "
               "is not al实例化类lowed to be non变量是什么意思-lazy",
               cls-源码之家>nameForLogging());
        }
       // fixm源码年代e alswiftlyso disallow relocatable classes
       // We canappreciate't disallswiftlyow all Swift classes because of
       // classes like Swift.__EmptyArrayStorage
      }
     realizeClas实例化类sWithoutSwift(cls, niswifterl);
    }
  }
 ts.log("IMAGE TIMES: realize non-lazy c源码下载lasses");
 // Realize newly-resolved future classes, i变量的界说n case CF manipulates them
 if (resolvedFutureClasses) {
   for (i = 0; i < rapp下载esolvedFutureClassCount; i++) {
     Class cls变量的界说 = resolvedFutureClasses[i];
     if (cls->isSwiftStable()) {
       _objc_fatal("Swiftappetite clswift国际结算体系ass is not allowed to be future");
      }
     ///调试代码 确定是咱们自界说的类
     const char *mangledName = cls源码是什么意思->nonlazyMangledNswiftcode是什么意思中文ame();
     const char *customerClassName = "JSPerson";
     if (strcmp(mswift怎样读angledName, customerClassName) == 0) {
       //打印类名
       printf("%s -: realize future classes要研讨的类: - %sn",__func__,mangledName);
      }
     realizeClassWit实例化类houtSwift(cls, nil);
     cls->setInstancesSwiftRequireRawIsaRecursively(false/*inherited*/);
    }
   free(resolvedFutureClasses);
  }
 ts.log("IMAGE TIMES: realize future classes");

在两行printf的当地打断变量泵点,作业源码程序,看是否实施到断点方位。发现打印了_read_images -:源码之家 non-lazy classes要研讨的类: - JSPerson,代码实施到了non-lazy classes,里面类加载的中心代码在realizeClassWithoutSwift函数,咱们持续根究realizeClassWithoutSwift函数。

realizeClassWithoutSwift剖析

操作之前的ro

咱们从上到下顺次阅读代码,定位到auto ro = (const class_ro_t )cls->data();,由于roclean Memory里的数据咱们比较活络,咱们在图示方位打断点:

iOS底层-类的加载(中)

运用LLDB调试程序,检查ro里的信息:

(lldb) p ro变量泵
(const class实例化是什么意思_ro_t *) $0 = 0x00000001000080c0
(lldb) p *$0
(const class_ro_t) $1 =实例化目标 {
flags = 0
instanceStaapp是什么意思rt = 8
insta实例化目标的关键字nceSize = 16
reserved = 0
 = {
 ivarLayout = 0x0000000000000000
 nonMetaclass = nil
}
name = {
 std::__1::atomicswiftcode代码查询<const char *> = "JSPerson" {
  Value = 0x0000000100003db0 "JSPerson"源码下载
  }
}
b源码a实例化需求seMethodList = 0x0000000100008108
baseProtoc源码怎样做成app软件ols = 0x0000000000000000
ivars = 0x0000000100008170
weakIvarswift怎样读Layout = 0x0000000000000000
baseProperties = 0x变量与函数0000000100008198
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $1.baseMethodList
(void *constapple) $2 =变量 0x0000000100008108
(lldb) p *$2变量名的命名规矩
(lldb)

经过打印咱们发现此时ro里的baseMethodList为空,现在还不清楚什么时分赋值的,咱们application持续根究。

rw的赋approach

接下来便是对rw的赋值app是什么意思,留意rwdirty Memory

if (ro->flags & RO_FUTURE) {
  // This was a future class. rw data is already allo源码交易平台排行cated.
  rw = cls->data();
  ro = cls->data()-&gswift代码t;ro();
  ASSERT(!is变量名的命名规矩Meta);
  cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
  // Normal class. Allocat变量的界说e writeable class data.
  rw = objc::zalloc<class_rw_t>();
  rw->set_ro(ro);
  rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
  cls-&gt变量之间的联系;setData(rw);
}

isa和su实例化目标有几种办法perClass赋值

swiftly边的代码便是对isasuswift怎样读perClass的赋值:

supercls = realizeClassWithoutSwift(remapClass(clswiftcode是什么意思中文s->getSuperclass()), nilapplication);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil源码本钱);
​
#if SUPPORT_NONPOINTER_ISA
 if (isMeta) {
   // Metaclasses do not nswift代码eed any features from non pointer ISA
   // This allows f变量名or a faspath for classes iswift代码n objc_retain/objc_release.
   ///元类 不是nswiftlyon pointer ISA
   cls->setInstancesRequireRawIsa();
  } el实例化一个类se {
   // Disable non-poinswift代码ter isa for some classes and/or platfo源码之家rms.
   // Setappstore instancesRequir变量名eRawIsa.
   bool instancesRequireR变量名awIsa = cls->instancesRequireRawIsa();
   bool rawIsaIsInheriteappstored = false;
   static bool hackedDispatch = false;
​
   if (DisableNonpointerIsa) {
     //假设咱们设置变量不运用 non pointer ISA 也会是纯的isa
     // Non-pointer isa disabled变量的指针其意义是指该变量的 by eapproachnvironment or app SDK version
     instancesRequireRawIsa = true;
    }
   else if (!hackedDispatch && 0 == strcmp(ro-swift体系>getName(), "OS_object"))
    {
     // hack for libdis变量patch et al - isaappreciate also acts as vtable pointer
     hackedDispaAPPtch = true;
     instancesRequireRawIsa = true;
    }
   else if (suappstorepercls && supercapp是什么意思ls->getSuperclass() &&
        su实例化类percls-&g变量名t;instancesRequ实例化目标的关键字ireRawIsa())
    {
     // This is also propagated by addSubclass()
     // but nonpointer isa setup needs it earlier.
     // Special case: instancesRequireRawIsa does not propagate
     // from root class to root metaclass
     instappleancesRequireRawIsa = true;
     rawIsaIsInherited = true;
    }
​
   if (instancesRequireRawIsa) {
     cls->setInstancesappleRequappreciateireRawIsaRecursively(rawIsaIsInherited);
    }
  }
// SUPPORT_NONPOINTER源码之家_ISA
#endif
 // Updat源码编辑器e superclass answift怎样读d metaclass in case of rapp下载emapping
 cls->setSuperclass(supe实例化需求rcls);
 cls->swiftcode是什么意思中文initClassIsa(metacls);

realizeClassWithoutSwift函数最终会调用methodizeClas实例化目标有几种办法s变量之间的联系,咱们下一小节根究methodizeClass

methodizeClass剖析

methodizeClass断章取义便是源码怎样做成app软件对办法的处理。

static void metho变量dizeClass(Class cls, Cl源码年代坑人ass previously)
{
 runtimeLock.assertLocked();
 bool isMeta = cls->isMetaClass();
 auto rw = cls-&gt源码交易平台排行;data();
 auto ro = rw-&gappetitet;ro();
 auto rwe = rw->ext()源码下载;
 // Methodizing for the first time
 if (PrintConnectin实例化一个类g) {
   _objc_inform("CLASS: methodizing class '%s' %s",
          cls->nameForLog变量是什么意思ging(),swift代码 isMeta ? "(meta)" : "");
  }
 ///调试代码 确定是咱们自界说的类
 consSwiftt char *mangledName =swiftkey cls->nonlazyMangledName(swiftcode是什么意思中文);
 const char *customerClassName = "JSP变量泵ersonapp是什么意思";
 if (strcmp(mangledName, custo源码交易网站源码merClassName) == 0) {
   //打源码之家印类名
   if (!isMeta) {
     prin源码本钱tf("%s -: non-lazy classes要研讨的类: - %sn"源码年代坑人,app是什么意思__func__,mangledName);
    }
  }
 // Install methods and properties that the class implements itself.
 //取出办法列表
 method_list_t *list = ro->baseMethods();
 if (list变量名) {源码之家
   prepareMethodLappreciateists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
   if (rwe) rwe-&g变量是什么意思t;methods变量类型有哪些.attachLists(变量类型有哪些&aapplemp;list, 1);
  }
 property_list_t *proplist = ro-&g源码怎样做成app软件t;baseProperties;
 if (r源码编辑器we && proplist) {
   rwe->propapplicationerties.变量的指针其意义是指该变量的attachLiSwiftsts(&proplist, 1);
  }
 protocol_list_t *protolist = ro->baseProtocols;
 if (rwe && protolist) {
   rw实例化一个类e->pro源码交易平台排行tocols.attachLists(&protolist, 1);
  }
 // Root classes get bonus method implementations if theyappreciate don't have
 // them already. These apply before category replacements.
 if (cls->isRootMetaclass()) {
   // roSwiftot metaclass
   addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
  }
 // Attaswiftcode代码查询ch categories.
 if (源码编辑器previously) {
   if (isMeta) {
     objc::unattachedCategories.attachToClass(cls, previously,
                          ATTACH_METACLASS);
    } else {
     // When a class relocates, categories with class methods
     // may be registered on the class itself rather than on
     // the metaclass. Tell attachToClass to look for those.
     objc::unattachedCategories.attachToCl实例化目标的关键字ass(cls, pappearreviously,
                          ATTACH_CLAswift怎样读SS_AND变量名_METACLASS)实例化需求;
    }
  }
 objc::unattachedCat源码之家egories.attachToClass(cls, cls,
                      isMeta ? ATTACH_METACLASS : ATTACH_appearCLASS);
​
#if DEBUG
 // Debug: sanity-check all SELs; log method list contents
 for (coswift国际结算体系nst auto& me实例化目标的关键字th : rw->me源码thods()) {
   if (源码年代坑人PrintConnecting) {
     _objc_inform("METHOD实例化类 %APPc[%s %s]", isMeta ? '+' : '-',
            cls->nameForLogging(), sel_getName(m变量类型有哪些eth.name()));
    }
   ASSERT(sel_swifterregisterName(sel_getNappleame(meth.name())) == meth.name(源码编辑器));
  }
#endif
}

断点进入图示方位,此时办法列表仍是不能源码是什么意思打印

iOS底层-类的加载(中)

prepareMethodLists

咱们持续根究,后边实施prepareMethodLisswiftlyts函数。

static void
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
         bool baseMethods, bool methodsFromBundle, const char *w源码编辑器hy)
{
 runtimeLock.assertLo变量的指针其意义是指该变量的cked();
 if (addedCount == 0) return;
 // There exist RR/AWZ/Core special cases fappointmentor some class's base methods.
 /变量之间的联系/ But this code should never need to scan base methods for RR/AWZ/Core:
 // default RR/AWZ/Core cannot be set before setInitialized().
 // Therefore源码本钱 we needAPP not handle any special case源码年代坑人s here.
 if (baseMethods) {
   ASSERT(cls->hasCustomAWZ() && cls->hasCuswifters变量值tomRR() && cls->hasCustomCore());
  } else if (cls->cache.isConstant实例化是什么意思OptimizedCac变量名he()) {
   cls-&swiftcode是什么意思中文gt;setDisallowPreoptCachesRecursively(why);
  } else if (cls->allowsPreoptInlinedSels()) {
#if CO变量NFIG_USE_PREOPT_CACHES
   SEL *sels = (SEL *)objc_opt_offsets[OBJC_OPT_INLINED_METHODS_START];
   SEL *sels_end = (SEL *)objc_opt_offsets[OB变量JC_OPT_INLINED_MapproachETHODS_END];
   if (method_list变量的指针其意义是指该变量的s_contains_any(addedLists, addedL源码ists + addedCount, sels, sels_end - sels)) {实例化数组
     cls->setDisallo变量泵wPreoptInlinedSelsRecursively(why);
    }
#endif
  }
 // Add method lists to array.
 // Reallocate un-fixed method lists.
 // Tapp下载he new methods are PREPENDED to the method list array.
​
 for (int i = 0; i < addedCount; i++) {
   method_list_t *mlist = addedLists[i];
   ASSERT(mlappearist);
   // Fixup selectors if necessary
   if (!mlist->isFixedUp()) {
     //中心代码
     fixupMethodList(mlist, methodsFswiftlyromBundle, true/*sort*/);
    }
  }
​
 // If the class is initialized,源码年代坑人 then scan for method implementations
 // tracked by the class's flags. If it's not initialized yet,
 // then objc_class::setInitialized() will take car源码是什么意思e of it.
 if (cls->isInitialized()) {
   objc::AWZScanner::scanAddedMe变量thodLists(cls, addedL变量类型有哪些ists, addedCount);
   objc::appleRRScanner::scanAddedMethodLists(cls, add实例化目标有几种办法edLists, addedCount);
   objc::CorswiftereScanner::sc变量泵anAddedMetho源码年代坑人dLists(cls, add实例化目标是什么意思edLists, addedCount);
  }
}

中心调用是fixupMethodList函数。

fapp是什么意思ixupMeappstorethodList

static void
fixupMethodLisappreciatet(method_list_t *mlist, bo源码之家ol bu实例化目标有几种办法ndleCopy, bool sort)
{
 runtimeLock.assertLocked();
 ASSERT(!mlist->isFixedUp());
 // fixme lock less in attachMethodLists ?
 // dyld3 may have already uniqued, but not sorted, the list
 if (!mlist->isUniqued()) {
   mutex_locker_t lock(selLock);
 
   // Unique selectors in list.
   for (auto&amp源码年代坑人; meth : *mlist) {
     const char *name = sel_cna源码之家me(meth.name());
     meth.setNa变量名的命名规矩me(sel_registerNameNoLock(name, bundleCopy));
    }
  }
 // Sort by sel变量名的命名规矩ector address.
 /源码交易网站源码/ Don't try to sort small lists, as they're immutable.
 // Don't try to sort big lists of nonstandard size, as stabswiftcode是什么意思中文le_sort
 // won'tapproach copy the entries properly源码之家.
 if (sort &&appointment !mlist->isSmallswift体系List() &&变量之间的联系 mlist->entsize() == method_t::bigSize) {
   method_t::So变量rtBySELAddress sorter;
   std::stable_sort(&mlist->begin()->bi实例化一个类g(), &mlist->end()->big(), sor变量之间的联系ter);
  }
 // Mark method list as uniqued and sorted.
 // Can't mark small lists, since they're immutableAPP.
 if (!mlist-&gt实例化类;isSmallList()) {
   mlist-&源码是什么意思gt;setFixedUp();
  }
}

中心的代码源码编辑器stable_sort,咱们别离打印排序前后办法列表,如图示

iOS底层-类的加载(中)

留意:这儿一定要先在realizeClassWithoutSwift判别好是咱们要研讨的JSPerson类,然后再看打印效果,否则体系类也会有许多打印,影响咱们剖析。

me实例化thodizeClass -: non-lazy classes要研讨的类: - JSPerson
****************sort之前 : say1 - 0x100003dda
sort之前 : say2 - 0x100003ddf
sort之前 : nickNamappointmente - 0x7fff73fb8a1c
sort之前 : setNickName: - 0x7fff73fb8362
****************sort之后 : say1 - 0x1swift体系00003dda
sort之后实例化需求 : say2 - 0x100003ddf
sort之后 : setNickName: - 0x7fff73fb8362
sort之后 : nickName - 0x7fff73fb8a1c

经过上面打印效果:

  • 排序前:say1appointment - 0x100003ddasay2 - 0x100003ddfnickName - 0x7fff73fb8a1csetNickName: - 0x7fff73fapp下载b8362
  • 排序后:say1 - 0x100003ddaswift代码是什么意思say2 - 0x100003ddfsetNickName: - 0x7fff73fb8362nickName - 0x7fff73fb8a1c
  • 排序是依实例化目标是什么意思据地址由低到高排序的。

小结

到现在为止,类的加载流程是:_read_im实例化数组ages->re实例化一个类alswift代码是什么意思izeClassWithoutSwiftapproach->methodizeClass->prepareMethodLists->fixupMethodL实例化目标ist

懒加载类和非懒加载类

咱们前面根究的其实都是非懒加载的类懒加载类非懒加载的类的差异便是是否完成了load办法

非懒加载

经过上面的剖析,咱们现已很清楚了,是在_objc_源码交易网站源码init办法里加载变量名的,也便是程序发起的时分APP。这也便是为什么变量之间的联系load办法过多,会影响咱们使用的发起速度

懒加载类

由于非懒加载类效率低,会影响咱们的发起速度,那懒加载类是什么时分加载的呢?咱们删掉JSPerson类的load办法,然后在main函数中实例化一个JSPerson实例

in实例化servlet类异常t main(int arg源码编辑器c, const charapplication * argv[]源码年代坑人) {
@autorelea变量值sepool {
JSPerson *p = [JSPerson alloc];
[p say1]app下载;
NSLog(@"Hello, World!");
}
return 0;
}

咱们首先在main办法里增加断点,实施程序。走到main函数之swift代码是什么意思后,然后再在realizeClassWithoutSwift增加断点:

iOS底层-类的加载(中)

断点走进来之后咱们bt打印调用栈信息:

iOS底层-类的加载(中)

发现调用是从lookUpImpOrForward开端。

所以咱们的结论是懒加载的类是在第一次被运用的时分加载的。

总结

  • 非懒加载类:程序作业时加载,_read_images->realizeClassWithoutSwift->metho实例化数组dizeClass->prepareMethodLists->fixupMethodList

  • 懒加载类:第一次运用时加载,lookUpImpOrForward->realizeClassWithoutSwift->变量与函数methodizeClass->prepareMethodLists->fixupMethodList

    咱们开发中经常会写分类,它是什么时分加载的及加载的流程,咱们下一篇再根究。

发表评论

提供最优质的资源集合

立即查看 了解详情