iOS面试攻略之 — 详解Objective-C runtime

原文地址:http://blog.securemacprogramming.com/2013/12/by-your-_cmd/

 
感谢翻译小组成员 wingpan热心翻译。本篇文章是我们每周推荐优秀国外的技术类文章的其中一篇。如果您有不错的原创或译文,欢迎提交给我们,更欢迎其他朋友加入我们的翻译小组(联系qq:2408167315)。
 
本文是我在  Alt Tech Talks: London 上关于 Objective-C runtime的演讲总结,如果你对Objective-C runtime感兴趣的话,应该看看这篇文章,特别是文章中的链接,一定会受益匪浅。 
 
什么是Objective-C runtime?
简单来说,Objective-C runtime是一个实现Objective-C语言的C库。对象可以用C语言中的结构体表示,而方法(methods)可以用C函数实现。事实上,他们差不多也是这么干了,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,Objective-C程序员可以在程序运行时创建,检查,修改类,对象和它们的方法。
 
 除了封装,Objective-C runtime库也负责找出方法的最终执行代码。当程序执行[object doSomething]时,不会直接找到方法并调用。相反,一条消息(message)会发送给对象(在这儿,我们通常叫它接收者)。runtime库给次机会让对象根据消息决定该作出什么样的反应。Alan Kay反复强调消息传递(message-passing)是Smalltalk最重要的部分( Objective-C根据Smalltalk发展而来),而不是对象: 
 
由于以前关于这个话题我创造了“对象”这个词,现在很多人都对这个概念趋之若鹜,这让我感到非常遗憾。
 
其实这里面更为重要的理念是“消息命令”(messaging),这才是Smalltalk的核心内容(现在尚有一些内容还没有全部完成)。日语中有个简短的单词叫做“ma”,它用来表示两个物体之间的东西,在英语中和它最相近的单词也许是“interstitial”。制造一个庞大且可扩展系统的关键是设计它各个模块之间的通信方式,而不是关注它的内部属性和行为。 
 


 
 
实际上,在一篇介绍 Smalltalk虚拟机的文章里,这门编程技术被叫做消息传递或者消息传送范式。“面向对象”通常用来描述内存管理系统。
 
在演讲和文章中都使用ObjC runtime这个词,看似只有一个,实际上存在很多runtime库。虽然它们都支持对象的自省检查和消息接收,但是它们却有不同的特性和实现方式(例如,同样是发送消息,Apple的runtime用一步完成,而GNU runtime会先查询这些消息,然后执行查找到的函数分两步完成)。以下所有的讨论,都是基于Apple的最新runtime库(苹果公司在OSX 10.5和iOS发布时的版本)。 
 
在那次演讲中,我决定研究runtime库某些领域的功能。我找了一些希望更透彻了解的东西,然后把它们做成问答的形式组成我的演讲。
 
动态创建类
 
如何实现Key-Value Observing?
 当我在准备这次演讲时,一篇叫做 KVO considered harmful 的文章开始拥有很多拥趸。它提出了很多对KVO正确的批评,但相对于舍弃观察者模式不用,我更想探索出一种新的实现方式。 
 
KVO实现观察者模式的关键是它偷偷摸摸将被观察对象的类改变了,它子类化原来的类后,就能够自定义该对象的方法来调用KVO的回调方法。这些都是通过 objc_duplicateClass这个方法完成,但很遗憾,这个方法并不公开,我们无法私自调用。 
 
条条大路通罗马,好在除了objc_duplicateClass,还有其他方法可以通过使用秘密子类化的方式实现观察者模式,比如创建和注册“class pair”。那么什么是class pair呢?对于Objective-C的类来说,都有一对Class的对象来定义它:Class对象定义了这个类的实例方法,而metaclass定义了这个类的类方法。所以每个class其实是它metaclass的单例。 
 
这个代码展示了观察者模式的工作原理。当你给对象增加观察者时,这个对象首先会检查自己是否可被观察,如果是,它会新创建一个类,用我们自己的-dealloc替代原来类的方法,同样它也会把-class方法替换掉,类似于KVO被观察对象,当你访问被观察对象的类名时,返回的是它原来的类名,而不是新生成的类。
 
创建完类后,我们需要照着 Key-Value Coding为属性增加一个setter方法:这个setter方法会获取这个属性修改前的值和修改后的值,然后调用block形式的回调函数,将这两个值告诉观察者。代码中根据我们的意愿,这个block可以异步调用。 
 
请注意, -addObserverForKey:withBlock:会使用s object_setClass() 将被观察对象的类替代为新组建的类。这样做最主要的目的是将消息转变为方法的方式改变,但是这需要非常小心,原来的类和新的类必须有相同的成员变量布局。因为成员变量也是用过runtime访问,修改某个对象的类可能导致runtime无法找到对应的变量。 
 
我们在存储观察者集合时遇到些麻烦,因为没地方去存它们。给ObserverPattern这个类增加成员变量不起作用,因为根本没有生成这个类的对象。被观察对象的成员变量是它原来类的,它并没有考虑过这些观察者。 
 
Objective-C runtime通过引入  associated objects 帮助我们摆脱这个困境。在runtime里,理论上所有对象都可以拥有包含其他对象的字典。通过associated references,被观察对象可以存储和访问他们的观察者,而不需要额外的成员变量。
 
如果你运行多次后,你会发现ObserverPattern 还是有点小毛病的。由于观察者回调是异步调用的,观察者接
 
收到的变化事件也是乱序的。这意味着观察者其实无法区分被观察属性的最终状态是什么,回调中的新值可能早已被修改。我这样做的目的是为了说明在KVO中同步调用回调其实是个有用的特色,并非bug。 
 
创建对象
 
那些额外的字节都是干啥用的?
当你创建一个 Objective-C对象时,runtime会在实例变量存储区域后面再分配一点额外的空间。这么做的目的是什么呢?你可以获取这块空间起始指针(用 object_getIndexedIvars),然后就可以索引实例变量(ivars)。好吧,下面我会使用自定义数组来说明一下索引ivars的用处。 
 
让我们创建一个数组!从这个SimpleArray中可以看到两件事情:最明显的一件是它使用了 类簇模式。当使用+alloc方法返回对象时,一般情况下已经为这个对象分配了所有的内存,但是在这个例子中,在+alloc时并不知道需要多大的内存空间。只有当调用了 -initWithObjects:count:以后,才能根据数组内对象数量计算出这个数组需要多大的内存,所以+alloc只是返回一个占位符,只有在初始化后才会分配和返回真正的数组对象。 
 
或许你会问为什么我们要用类簇把事情搞那么复杂,使用 calloc()另外分配一块大小合适的缓存,然后把那些对象指针存到里面不就得了?答案是希望利用 局部性原理提高访问性能。从数组的设计上我们可以看出,每次数组指针被访问时,之后会有很大几率访问到缓存指针,所以把它们肩并肩的放入内存意味着找到其中一个就是找到了另外一个。 
 
消息派发
 
消息如何转发?
Objective-C其中一个强大特性是对象不需要实现某个方法,尽管它在编译时声明了该选择符(selector)。但它可以在运行时再决定方法实现,或者将这些消息转发给其他对象,或者发出异常,亦或做一些其他事情。但是这个特性的某些方面曾经一直困扰我:消息转发(message forwarding)会调用 -forwardInvocation:,然后传入一个NSInvocation 对象。但是这个NSInvocation 类是在Foundation库中定义的,难道说runtime工作需要Foundation配合? 
 
我试着挖掘其中的原因,发现答案并不是我想的那样,runtime不需要知道Foundation。runtime会让程序定义转发函数(forwarding function),当 objc_msgSend()无法找到该selector的实现时,那个转发函数就会被调用。程序一启动,CoreFoundation就将 -forwardInvocation:定义成转发函数。 
 
让我们来 创建一个Ruby!当然并不是真的实现完整的Ruby,Ruby有一个叫做#method_missing的函数,当对象收到一个它没有实现的消息时,这个函数就会被调到,这和Smalltalk的做法比较相似。使用objc_setForwardHandler,我们也能在Objective-C的类中实现类似Ruby的methodMissing:方法。 
 
总结
Objective-C runtime可以有效的帮助我们为程序增加很多动态的行为。一些开发者除了使用method swizzling帮助调试程序,并不会在实际程序中使用它,但runtime编程的确有很多功能,它应该成为实际应用代码编写的重要工具。
 
Go GMP 调度器深度解析:从运行时原理到可复核的并发边界 Goroutine 的价值是把并发等待表达得足够廉价,使服务能把 CPU 用在真正可运行的工作上。它的边界同样明确:当到达持续超过完成时,系统必须选择在哪里排队、排多久、何时拒绝以及如何取消。高质量的并发设计不从“该开多少 goroutine”开始,而从可观测、可验证的容量合同开始:入口接受多少、队列允许等多久、下游承受多少、失败如何收敛、恢复如何验收。GMP 是实现这套合同的运行时基础,不是绕过它的理由。 阅读详情

相关推荐

GPU/SoC Power & Performance 架构进阶(11):Linux Power Management、BPMP/SMU 与 GPU 控制链

本文系统梳理了Linux电源管理框架(cpufreq、cpuidle、devfreq、runtime_pm)在GPU/SoC中的应用,结合NVIDIA Jetson(BPMP)与AMD GPU(SMU/PMFW)的公开案例,解析软硬件协同的功耗控制链。重点强调OPP框架作为性能请求与硬件执行的桥梁,指出实际频率/电压需跨层验证。通过只读探索与请求追踪,揭示控制路径中各环节的卡点分析方法,并警示Runtime PM中的竞态风险与引用管理关键性,为嵌入式系统能效优化提供可迁移的架构视角。

元直的博客 12

iOS大解密:玄之又玄的KVO

导读: 大多数 iOS 开发人员对 KVO 的认识只局限于 isa 指针交换这一层,而 KVO 的实现细节却鲜为人知。 如果自己也仿照 KVO 基础原理来实现一套类 KVO 操作且独立运行时会发现一切正常,然而一旦你的实现和系统的 KVO 实现同时作用在同一个实例上那么各种各样诡异的 bug 和 crash 就会层出不穷。 这究竟是为什么呢?此类问题到底该如何解决呢?接下来我们将尝试从汇编层面来入手以层层揭开 KVO 的神秘面纱… 1. 缘起 Aspects SDMagicHook 开源之后很多小伙伴在.

weixin_48726650的博客 621

SAP MRKO与MIRO的对比分析:为何寄售结算需要定制开发?

本文深入分析了SAP系统中MRKO与MIRO在寄售结算中的功能差异,揭示了标准MRKO在财务控制和业务流程上的局限性。通过定制开发实践,如BAdI增强和界面优化,企业可显著提升结算效率与准确性。文章还探讨了未来SAP S/4HANA在寄售结算中的智能化趋势,为相关企业提供技术参考。

weixin_29300241的博客 419

详解Objective-C runtime

原文链接 :http://www.cocoachina.com/gamedev/misc/2014/0106/7658.html 发布于:2014-01-06 11:28阅读数:958 本文是我在 Alt Tech Talks: London 上关于 Objective-C runtime的演讲总结,如果你对Objective-C runtime感兴趣的话,应该看看这篇文章,特

冷胜任 的专栏 1551

飞凌OK3588-C Linux R4系统下MIPI YUV摄像头CSI尺寸错误排查与极性适配方案

本文详细介绍了在飞凌OK3588-C平台的Linux R4系统下调试MIPI YUV摄像头时遇到的'csi size err'错误排查与极性适配方案。通过分析信号极性、驱动参数调整及FPGA协同调试,提供了从硬件检测到系统级调试的完整解决方案,帮助开发者快速解决类似问题。

bean的博客 258

TI LP87745-Q1汽车雷达PMIC评估:从硬件设计到性能测试全解析

在汽车电子和高级驾驶辅助系统(ADAS)中,电源管理单元(PMIC)是确保传感器稳定可靠运行的核心。其工作原理在于集成多路高效电源转换器(如Buck、Boost)和精密监控电路,通过数字接口实现灵活配置与实时诊断。这项技术的核心价值在于为毫米波雷达等关键负载提供低噪声、高精度、满足严格时序与功能安全(ASIL)要求的供电方案,从而提升整个感知系统的信噪比与可靠性。其典型应用场景包括自动驾驶域控制器、车载传感器融合模块等。本文以德州仪器(TI)的LP87745-Q1专用PMIC及其评估模块(EVM)为例,深入

weixin_27017211的博客 311

NSDictionary 内部结构、实现原理

首先咱们了解一下这几个概念:哈希表、时间复杂度、链表看了上面的文章,估计大家都懵逼了。。。好吧,正文来了NSDictionaryNSDictionary(字典)是使用 哈希表来实现key和value之间的映射和存储的, hash函数设计的好坏影响着数据的查找访问效率。数据在hash表中分布的越均匀,其访问效率越高。而在Objective-C中,通常都是利用NSString 来作为键值,其内部使用的...

fishmai的专栏 2459

从FPGA工程师视角看CXP-12:如何用Xilinx GTX/GTH收发器搞定一条50Gbps的工业相机数据流?

本文从FPGA工程师视角详细解析了如何利用Xilinx GTX/GTH收发器实现50Gbps的CXP-12工业相机数据流传输。通过协议分析、硬件设计要点和FPGA逻辑实现,帮助开发者高效构建高带宽工业视觉系统,特别适合4K/8K高分辨率图像处理需求。

weixin_42533622的博客 282

刨根问底KVO原理

转载链接:https://juejin.im/post/5c22023df265da6124157a25 介绍 KVO(NSKeyValueObserving)是一种监测对象属性值变化的观察者模式机制。其特点是无需事先修改被观察者代码,利用runtime实现运行中修改某一实例达到目的,保证了未侵入性。 A对象指定观察B对象的属性后,当属性发生变更,A对象会收到通知,获取变更...

weixin_30726161的博客 258

DINOv2 基于自定义数据集进行图片分类预测

(前提是安装好pytorch)1. pip安装2. 下载dinov2提供的预训练模型,需要自行前往网站上查找dinov2模型进行下载。模型需要下载三个文件:下载完成后将上述三个文件放置在本地一个名为dinov2_base的文件夹中即可。

sinat_34770838的博客 6665

OP-TEE虚拟化支持详解

OP-TEE虚拟化支持解析 OP-TEE提供实验性虚拟化方案,支持多虚拟机共享安全执行环境。核心特性包括: 配置选项:CFG_VIRTUALIZATION启用虚拟化,CFG_VIRT_GUEST_COUNT限制虚拟机数量并分配均等内存资源; Hypervisor协作:需实现虚拟机生命周期通知、SMC参数转换、内存固定等关键协议; 当前限制:仅支持Armv8架构,硬件资源共享有限,采用静态内存配额机制; 架构实现:通过MMU分区切换和扩展内存分配器实现多租户隔离,Nexus核心层管理虚拟机上下文。该方案适用于

Linux内核架构师 109

过招多家大厂提炼的iOS面试心经

前言 最近应该有很多小伙伴去跳槽面试的吧,相信各位有的已经顺利收到offer了,而有些则是碰壁了,那么我在这里给大家准备了相关面试资料,还有相关算法资料。想了解的可找我拿 ######2020年,整个资本市场风起云涌,大环境下,互联网更是风声鹤唳,大多数公司面临着裁员,结构重构,他们收紧资本,为自己取暖。在漫长的寒冬下,互联网人只有自己修炼内功,才能在寒风中屹立不倒。 ######作为一名iOS开发者,要时时刻刻保持学习的冲劲,新的知识每年都是海量增长,要学的东西真的太多太多。很多公司收紧资本,所以,对于找

henry_lei的博客 246

YOLOv11改进-卷积-引入小波卷积WTConv 解决多尺度小目标问题

1.首先,WTConv利用二维Haar小波变换对输入图像进行多级分解。低频分量 (LL):捕捉图像的低频信息,如整体形状或轮廓。水平高频分量 (LH):捕捉图像中的水平边缘信息。垂直高频分量 (HL):捕捉图像中的垂直边缘信息。对角线高频分量 (HH):捕捉图像的对角线细节。在每一级的小波变换中,图像被下采样(空间分辨率减半),但频率信息得到了更细的分解。递归地执行小波变换(称为多级分解)可以得到不同尺度下的频率分量。

qq_64693987的博客 1万+

100+篇技术文章推荐总有一篇你想看的

1.Class类的底层实现原理 - 链接 链接 2.Category分类的底层实现原理 - 链接 3.Block块的底层实现原理和使用 - 链接一 链接二 4.@autoreleasepool自动释放池的底层实现原理 autoreleasepool 5.KVO键值观察底层实现原理和使用 - 链接 链接 6.KVC简直编码的底层实现原理使用. 链接 7.Runtime机制的原理 链接 链接 链接...

weixin_34032792的博客 221

Apache Flink连载(一):Apache Flink是什么?

Apache Flink 是一个框架和分布式处理引擎,用于在。

qq_32020645的博客 1216

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

考研复试上机全攻略:从数据结构到考场实战的避坑指南

在计算机专业能力评估中,数据结构与算法始终是衡量编程功底的核心标尺,而OJ在线判题系统则通过严格的时空限制和边界测试,客观反映考生解决实际问题的工程能力。无论是链表操作、二叉树遍历,还是动态规划与图论模板,掌握这些基础知识的原理与实现,能显著提升代码的健壮性和运行效率。这一能力在考研复试上机环节尤为重要——院校通过机试筛选具备建模思维和调试技巧的候选人,且成绩往往直接影响录取结果。从C++/STL的高频用法到多组输入输出处理,从暴力骗分策略到递归爆栈规避,系统性的刷题路线和考场技巧,能够帮助考生在有限时间内

weixin_34163553的博客 366

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

消费级VR眼镜选购与上手指南:从原理到实践,打造家庭沉浸体验

虚拟现实(VR)技术通过模拟三维环境,为用户提供沉浸式交互体验。其核心原理在于利用头戴式显示设备、运动追踪和实时渲染技术,欺骗视觉与前庭系统,营造身临其境之感。这项技术的价值在于革新了娱乐、教育、培训等领域的交互方式,降低了体验门槛。在应用场景上,消费级VR设备已从专业领域走向家庭,成为游戏、社交和技能学习的平台。本文聚焦于Inside-Out追踪和无线串流两大关键技术,它们分别解决了VR设备的便捷定位与高性能内容传输问题,使得现代VR眼镜能够摆脱复杂的外部基站与线缆束缚,实现真正的即戴即用。通过理解这些基

weixin_30859423的博客 545

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

IOS底层面试题 Objective-c(Runtime、Runloop、Block、内存管理、多线程、性能优化等)

1. 一个NSObject对象占用多少内存? 系统分配了16个字节给NSObject对象。 通过malloc_size函数获得,该函数返回的是系统给该对象分配的内存大小,在64bit环境下,所获得的数值是16个字节的倍数 但NSObject对象只使用了8个字节的空间。 64bit环境下,可以通过class_getInstanceSize函数获得 ...

weixin_45043820的博客 1800

导出 ONNX 后 top-1 翻转:数值差 1e-3,先查 model.eval() 再比 opset

模型导出 ONNX 后数值偏移,边界样本 top-1 随之翻转。排查按导出模式、opset 版本与算子实现分三层展开并配复现脚本。该方法适用于部署前一致性验证,追求逐位一致仍需接受规范差异。

昨日种种,皆成今我。今日种种,皆成新我。 187

小白一键部署:VoiceStudio 本地语音工作室(Linux/Win/Mac)

VoiceStudio 是破十万星的开源本地语音工作室。本文在 Debian 13 实机用官方一行命令装上 0.5.7,记录 GPU 崩溃启动参数、Install local runtime、模型许可,以及 CPU 上 Voice Design 合成 7 秒 demo。与只做听写的 Hex 互补。

m0_56699208的博客 117

把 Agent 的判断与行动变成可恢复的软件事实|KDC 系列 工程篇

本文区分领域现实、业务判断事实和软件运行事实,提出业务因果链与运行事实链的双链结构;进一步将 Session、Harness 与执行环境解耦,区分 Session、Context、State、Memory 和 Knowledge,并以 Resume Contract、Progress Contract 与 Evaluation Contract 说明一次 Agent 运行如何被恢复、交接、验证和持续演进。

vivo互联网技术 332

导出ONNX后精度从95%跌到70%且零报错:先量级分诊再查tracing分支

导出 ONNX 后推理与 eager 静默不一致,指标下滑无报错。根因是 tracing 按样例输入固化分支,按差异量级分诊后定位控制流。

昨日种种,皆成今我。今日种种,皆成新我。 162

[iOS]Runtime2

为了让你在父类中依然能访问当前对象(也就是子类的实例),编译器在底层会生成一个结构体,叫 : 当调用 时,底层调用的函数是 : 拿着(也就是当前的子类对象)作为消息接收者,但是把方法查找的起点定位在了 (父类)这里需要注意的就是仍然是调用者自己,即先讲一下上篇没讲过的,我们如果缓存未命中,那我们就会进入慢速查找,现在我们来详细的讲解在进入慢速查找的瞬间会再看一遍方法列表,然后立刻调用加锁,因为多线程下别人正在动态添加方法或者扩容,不加锁会崩溃类就绪OC的机制就是在编译期只生成了 结构,当类首次被发送消息时(

wzm20070304的博客 248

重装 openvino、yaml-cpp

【代码】重装 yaml-cpp。

u010948546的博客 218

YLT 智能助手(小岳)· 02|运行时装配与依赖注入

本文详解YLT智能助手的“装配根”设计:通过五阶段分步初始化(治理→核心→能力→服务→生命),以显式顺序声明依赖,实现47个组件的有序装配。摒弃自动DI容器,采用手工注入避免循环依赖与生命周期错乱,用显式门面替代setattr动态绑定,确保可读性、可测试性与架构清晰。核心思想是“构造即依赖”,让100+对象在单进程内协同无冲突,为桌面Agent提供可复用的手工依赖注入范式。

u010972645的博客 211
上一篇: (译)KVO的内部实现
下一篇: Runtime (一) 之 —— Class、Selector、IMP 等概念
iteye_3205
博客等级 码龄8年 0粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值