当前位置: 首页 > news >正文

宝塔软件怎么做网站大连做网站企业

宝塔软件怎么做网站,大连做网站企业,网站开发业绩,杭州互联网公司50强本文来自网易云社区作者#xff1a;宋申易所以到底 objc_msgSend 发生了什么#xff1f;很多事情。看一下这段代码#xff1a;[self printMessageWithString:Hello World!];这实际上被编译器翻译成#xff1a;objc_msgSend(self, selector(printMessageWithStr…本文来自网易云社区作者宋申易所以到底 objc_msgSend 发生了什么很多事情。看一下这段代码[self printMessageWithString:Hello World!];这实际上被编译器翻译成objc_msgSend(self, selector(printMessageWithString:), Hello World!);我们顺着目标对象的 isa 指针查找看该对象(或者它其中一个父类)是否能响应 selector(printMessageWithString:) 选择器。假设我们在分派表(dispatch table)或者缓存中找到了该选择器我们会跟踪函数指针并执行它。所以 objc_msgSend() 永远不会返回它开始执行然后跟踪一个指向你的方法的指针然后你的方法返回这看起来就像 objc_msgSend() 返回了一样。Bill Bumgarner 在(Part 1, Part 2 Part 3)里描述了更多 objc_msgSend() 的细节。总结一下他的文章结合你看到的 Objective-C 运行时代码检查被忽略的选择器和短路。显然如果我们在垃圾收集下运行我们可以忽略 -retain-release 等调用。检查 nil 目标。和其他语言不同在 ObjC 里向 nil 发送消息十分合理并且有些情况下确实想要这么做。假如不是 nil 则继续……接下来在类中找到 IMP首先通过类缓存来查找如果找到就跟随指针跳转到对应的函数如果在缓存中找不到 IMP则通过分派表来查找如果找到就跟随指针跳转到对应的函数如果这两个地方都找不到 IMP则跳转到转发(forwarding)机制。这意味着最终你的代码会被编译器转译成 C 函数。你写的某个方法可能是这样-(int)doComputeWithNum:(int)aNum它会被转换成……int aClass_doComputeWithNum(aClass *self, SEL _cmd, int aNum)ObjC 运行时会通过调用这些方法的函数指针来真正执行方法。我曾说过你不能直接调用这些转译后的方法但其实 Cocoa 框架提供了一个获取函数指针的方法……// C function pointerint (computeNum *)(id, SEL, int);// methodForSelector is COCOA not ObjC Runtime// gets the same function pointer objc_msgSend getscomputeNum (int (*)(id, SEL, int))[target methodForSelector:selector(doComputeWithNum:)];// execute the C function pointer returned by the runtimecomputeNum(obj, selector(doComputeWithNum:), aNum);用这种方式你可以直接访问函数并且直接在运行时中执行它甚至绕过运行时的动态特性(为了确保指定的方法被执行)。ObjC 运行时也用这种方法来调用你的函数只是用了 objc_msgSend()。Objecetive-C 消息转发在 Objective-C 中发送消息给可能不能响应该消息的对象是合法的(可能是有意设计的)。苹果文档里提到可能的原因一个是模拟 Objective-C 并不原生支持的多重继承或者是你想把真正接受消息的类或者对象隐藏起来。这也是运行时很有必要的一件事。具体是这样的运行时搜索类缓存、类分派表以及父类的所有方法没有找到指定的方法。运行时对你的类调用 (BOOL)resolveInstanceMethod:(SEL)aSEL。这给你提供了一个方法实现的机会告诉运行时你已经解决了这个方法如果它应该开始进行搜索它将会找到方法。具体你可以这样做定义一个函数void fooMethod(id obj, SEL _cmd) {NSLog(Doing Foo);}然后可以使用 class_addMethod() 来解析它… (BOOL)resolveInstanceMethod:(SEL)aSEL {if(aSEL selector(doFoo:)) {class_addMethod([self class],aSEL,(IMP)fooMethod,v:);return YES;}return [super resolveInstanceMethod];}class_addMethod() 的最后一部分中的 v: 是该方法返回的内容也是它的参数。你可以在运行时指南的 Type Encodings 章节中了解可以放入哪些内容。如果我们不能解析该方法运行时会继续调用 - (id)forwardingTargetForSelector:(SEL)aSelector。它所做的是给你一个机会让运行时指向在另一个可以响应消息的对象。最好在开销更大的 - (void)forwardInvocation:(NSInvocation *)anInvocatio 方法接管之前调用例如{if(aSelector selector(mysteriousMethod:)) {return alternateObject;}return [super forwardingTargetForSelector:aSelector];}显然你不想从这个方法中返回 self因为这样会导致无限循环。运行时最后一次尝试发送一个消息发送到它的预定目标调用 - (void)forwardInvocation:(NSInvocation *)anInvocation。NSInvocation 本质上是一个 Objective-C 消息的的对象形式。一旦你有了一个 NSInvocation你基本上可以改变任何信息包括它的目标选择器和参数。例如你可以做- (void)forwardInvocation:(NSInvocation *)invocation {SEL invSEL invocation.selector;if([altObject respondsToSelector:invSEL]) {[invocation invokeWithTarget:altObject];} else {[self doesNotRecognizeSelector:invSEL];}}如果你的对象继承了 NSObject 默认情况下 - (void)forwardInvocation:(NSInvocation *)anInvocation 实现会调用 -doesNotRecognizeSelector:方法。你可以重写这个方法如果你想最后再做点什么。不脆弱的(Non Fragile)实例变量列表(ivars) (现代运行时)现代运行时新增加了不脆弱的(Non Fragile) ivars 的概念。当编译你的类的时候编译器生成了一个实例变量内存布局(ivar layout)来告诉运行时去那里访问你的类的实例变量们。这是一个底层实现细节ivars 是实例变量分别相对于你的对象地址的偏移量读取 ivars 的字节数就是读取的变量的大小。你的 ivar 布局可能看起来像这样(第一列是字节偏移量)这里我们画出了一个 NSObject 的实例变量内存布局。我们有一个继承了 NSObject 的类增加了一些新的实例变量。这没什么问题直到苹果发布了新的 Mac OS X 10.x 系统NSObject 突然增加两个新的实例变量于是你的自定义对象和 NSObject 对象重叠的部分被清除。如果 Apple 永远不改变之前的布局可以避免这种情况但如果他们那样做那么他们的框架就永远不会进步。在“脆弱的 ivars” 下你必须重新编译你从 Apple 继承的类来恢复兼容性。那么在不脆弱的情况下会发生什么呢?在不脆弱的 ivars 下编译器生成与脆弱 ivars 相同的 ivars 布局。然而当运行时检测到和父类有重叠时它会调整偏移量以增加对类的补充保留了在子类中添加的内容。Objective-C 关联对象(Associated Objects)Mac OS X 10.6 Snow Leopard 中引入了关联引用。Objective-C 没有原生支持动态地将变量添加到对象上。因此你需要竭尽全力构建基础架构以假装正在向类中添加一个变量。在 Mac OS X 10.6 中Objective-C 运行时提供了原生支持。如果我们想给每个已经存在的类添加一个变量比如 NSView我们可以这样做#import //Cocoa#include //objc runtime api’sinterface NSView (CustomAdditions)property(retain) NSImage *customImage;endimplementation NSView (CustomAdditions)static char img_key; //has a unique address (identifier)- (NSImage *)customImage {return objc_getAssociatedObject(self,img_key);}- (void)setCustomImage:(NSImage *)image {objc_setAssociatedObject(self,img_key,image,OBJC_ASSOCIATION_RETAIN);}end你可以在 runtime.h 看到。如何存储传递给 objc_setAssociatedObject() 的值的选项/* Associated Object support. *//* objc_setAssociatedObject() options */enum {OBJC_ASSOCIATION_ASSIGN 0,OBJC_ASSOCIATION_RETAIN_NONATOMIC 1,OBJC_ASSOCIATION_COPY_NONATOMIC 3,OBJC_ASSOCIATION_RETAIN 01401,OBJC_ASSOCIATION_COPY 01403};这些与你可以在property语法中传递的选项相匹配。混合 vTable 分发如果你看一下现代运行时代码你会看到这个(在 objc-runtime-new.m)。/************************************************************************vtable dispatch**每个类都有一个 vtable 指针。vtable 是一个 IMP 数组*所有的类的 vtable 中表示的选择器数量都是相同的。(i.e.*没有一个类有更大或更小的 vtable).*每个 vtable 索引都有一个关联的蹦床该蹦床在接收者类的*vtable 的该索引处分派给 IMP(检查 NULL 后)。分派*fixup 使用了蹦床而不是 objc_msgSend.*脆弱性vtable 的大小和选择器列表在启动时已经设定好了。*编译器生成的代码无法依赖于任何特定的vtable配置甚至*根本不使用 vtable 调度。*内存大小如果一个类的 vtable 和它的父类相同(i.e. 该类*没有重写任何 vtable 选择器), 那么这个类直接指向它的父*类的 vtable。这意味着被选中包含在 vtable 中的选择器应*该有以下特点*(1) 经常被调用但是 (2) 不经常被重写。*特别的是-dealloc 是一个坏的选择。*转发: 如果一个类没有实现 vtable 中的部分选择器, 这个类的*vtable 中的这些选择器的 IMP 会被设置成 objc_msgSend。*initialize: 每个类保持默认的 vtable(总是重定向到*objc_msgSend)直到其 initialize 初始化方法完成。否则*一个类的第一个消息可能是一个 vtable 调度而 vtable*蹦床不包括 initialize 初始化检查。*改变: Categories, addMethod, 和 setImplementation 如果影响*到了 vtable 的选择器类和所有的子类的 vtable 都将强制重建。**********************************************************************/这背后的思想是运行时试图在这个 vtable 里面存储最常被调用的选择器这可以给 app 加速因为这比 objc_msgSend 使用了更少的指令。这个 vtable 包含 16 个最常被调用的选择器占据了绝大部分全局调用的选择器。你可以看到垃圾回收 app 和非垃圾回收 app 的默认选择器都是什么。static const char * const defaultVtable[] {allocWithZone:,alloc,class,self,isKindOfClass:,respondsToSelector:,isFlipped,length,objectForKey:,count,objectAtIndex:,isEqualToString:,isEqual:,retain,release,autorelease,};static const char * const defaultVtableGC[] {allocWithZone:,alloc,class,self,isKindOfClass:,respondsToSelector:,isFlipped,length,objectForKey:,count,objectAtIndex:,isEqualToString:,isEqual:,hash,addObject:,countByEnumeratingWithState:objects:count:,};那么你怎么知道是否使用了 vtable 中的方法了呢你会在调试的堆栈跟踪中看到以下几个方法。这些方法你可以看成调试版的 objc_msgSend()。objc_msgSend_fixup 代表 runtime 调用一个方法并正要把它加入到 vtable 中。objc_msgSend_fixedup 代表你调用方法曾经在 vtable 中现在已经不在里面了。objc_msgSend_vtable[0-15] 代表上述 vtable 中的一个常用方法。runtime 可以随意分配或取消它想要的值。所以这一次 objc_msgSend_vtable10 对应于 -length 方法下一次运行可能对应方法就变了。总结我希望你喜欢这些这篇文章大体上组成了我在我给 Des Moines Cocoaheads 的 ObjC 演讲中提到的内容。ObjC 运行时写的很棒它提供了许多我们在 Cocoa / Objective-C 中习以为常的特性。如果你还没看过 Apple 的 ObjC 运行时文档希望你去看一看。谢谢网易云免费体验馆0成本体验20款云产品更多网易研发、产品、运营经验分享请访问网易云社区。
http://www.huolong8.cn/news/32315/

相关文章:

  • 手机网站好还是h5好专业的南昌网站建设
  • 深圳企业建站公司网站系统性能定义
  • ip开源网站fpga可以做点什么用玄武网站建设
  • 免费安全正能量网站大全路由器优化大师
  • 网站建设与维护工作北京高端网站公司哪家好
  • 免费推广网站在线做图片的软件
  • 网站制造制作网站公司推荐
  • 青浦区网站建设域名网安备案
  • 看上去高端的网站网站建设和网站开发的区别
  • 汕头网站推广找哪里如何选择企业网站建设
  • 正规网站制作全包孝感房地产网站建设
  • 网站建设 素材北京工业产品设计公司
  • 三网合一网站开发如何用html制作一个投票网页
  • 建站平台 phpwind网站建设 电子书
  • 使用php做网站wordpress最受欢迎的主题
  • 长沙建站价格wordpress优点缺点
  • 刷会员网站怎么做怎么在淘宝上做网站
  • 网站建设合同约定三年后wordpress获取文章发表时间
  • 厚瑜网站建设做跨境电商的人才网站
  • 深圳网站建设q.479185700惠wordpress黄聪文件上传
  • 如何让网站快速收录你成都黑帽seo
  • 湛江做网站制作博客网站源码
  • 建设管理网站首页农业特色网站建设
  • 网站前端用什么语言在线详情页制作
  • 官方网站下载免费软件施工企业如何发展新质生产力
  • 中国建筑网官网一级建造师管理优化前网站现状分析
  • 网站开发 面试wordpress调用百度网盘视频播放器
  • 哪些网站的网站怎么做的怎么创网站赚钱
  • 云南网站设计网站搭建用什么软件
  • 有什么做美食的视频网站网站怎么做黑链接