`
miss大为
  • 浏览: 82540 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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编程的确有很多功能,它应该成为实际应用代码编写的重要工具。
 
  • 大小: 133.1 KB
分享到:
评论

相关推荐

    Object-C_Runtime

    ### Objective-C_Runtime 运行机制详解 #### 一、Objective-C 概览 Objective-C是一种结合了C语言和Smalltalk面向对象技术的编程语言。它最初由Brad Cox和Tom Love在1980年代初开发,并由Stepstone公司进一步发展...

    Runtime Code Injection for Objective-C & Swift.zip

    在iOS应用开发中,Objective-C与Swift的运行时特性为我们提供了丰富的可能性,其中之一就是运行时代码注入。本文将深入探讨这个主题,帮助开发者理解如何利用这一技术来增强应用的功能和灵活性。 运行时代码注入...

    Runtime 学习详解

    本文将深入探讨Objective-C Runtime的学习详解,帮助开发者更好地理解和利用这个强大的工具。 1. **类与对象** - **类的定义与结构**:Objective-C中的类是元数据结构,它描述了对象的属性(实例变量)和行为...

    Objective-C 思维导图.pdf

    ### Objective-C 思维导图知识点详解 #### 1. 基础概念 - **1.1 简介** - **什么是 Objective-C**:Objective-C 是一种通用、面向对象的编程语言,它是在 C 语言的基础上扩展而成的。这种语言的主要特点是支持面向...

    iOS2018面试题

    根据给定的文件信息,以下是对“iOS 2018面试题”中涉及的知识点进行的详细解析: ### 技术基础知识 1. **Objective-C为何被称为动态语言:** - Objective-C作为一门面向对象的编程语言,其动态特性主要体现在...

    iOS面试题

    ### iOS面试题详解 #### 1. UIView与CALayer的区别 - **定义与层次:**UIView和CALayer作为iOS开发中极为重要的两类视图层组件,它们分别处于不同的抽象层次。UIView是UIKit框架中用于构建界面的核心类,而CALayer...

    iOS面试题合集

    ### iOS面试题合集知识点详解 #### 一、iOS中的锁机制 - **知识点概述**:iOS开发过程中,锁机制是实现多线程同步的重要手段之一。常用的锁机制包括互斥锁(`@synchronized`)、读写锁、NSLock、NSRecursiveLock等...

    ArcGIS Runtime SDK for ios 10.2.5

    - ArcGIS Runtime SDK 可以轻松与Objective-C和Swift项目集成,适用于iOS的各种设备和操作系统版本。 - 兼容其他Apple框架和服务,如CoreLocation、MapKit等,便于扩展应用功能。 8. **安全性与授权**: - SDK...

    IOS开发基本知识

    ### IOS开发基本知识详解 #### 一、Objective C入门概览 Objective-C是一种结合了C语言特性和面向对象编程(OOP)能力的编程语言。它最初由Brad Cox和Tom Love在1983年设计,并在苹果公司的Mac OS X和iOS操作系统中...

    IOS数据一键存储框架

    这个框架可能是通过集成FMDB库和Objective-C的runtime技术来实现的。 **描述详解:** 描述中提到的"YUDBFramework"是一个基于(FMDB + runtime)的数据库操作框架。FMDB是iOS平台上广泛使用的SQLite数据库的Objective...

    ios 百度面试题目

    ### 百度iOS面试知识点详解 #### 自我介绍与项目经验 - **自我介绍**:在面试时,自我介绍不仅仅是简单地讲述个人信息,更重要的是通过介绍自己的经历、技能以及成就来展示自己的能力和潜力。 - **项目经验**:面试...

    IOS Object-C 中Runtime详解及实例代码

    在iOS和macOS开发中,Objective-C的Runtime提供了强大的功能,包括消息传递、动态方法解析、元数据访问等。下面将详细介绍Runtime的一些关键概念和常见用法。 1. **消息传递(Message Dispatch)** Objective-C的...

    objc-runtime-master.zip

    Objective-C(简称OC)是一种基于C语言的面向对象编程语言,它是Apple的iOS和macOS开发平台的核心语言。在深入理解OC编程时,Objective-C的运行时(Runtime)系统是不可或缺的一部分。"objc-runtime-master.zip"包含...

    iOS 最新面试总结题库,欢迎观看.docx

    Runloop是iOS系统中用于管理线程运行的核心机制,而Runtime则是Objective-C语言的底层运行时系统,涉及到消息传递和方法解析等重要概念。 Runloop的理解: Runloop是一个持续运行的循环,它的主要任务是调度工作并...

    详解iOS的冲顶大会辅助

    总的来说,开发iOS的冲顶大会辅助工具需要掌握的知识点包括:iOS应用逆向工程,Objective-C runtime,UI自动化,KVO机制,以及可能的图像识别技术。这不仅要求开发者具备扎实的iOS编程基础,还需要一定的逆向分析和...

    iOS最新面试题及参考答案

    以上内容涵盖了iOS开发中常见的技术知识点,包括Swift的基础概念、与Objective-C的对比分析、面向协议编程的理念以及Objective-C中的高级主题如Block的实现和KVO的原理等。对于准备面试的iOS开发者来说,这些都是...

    IOS开发入门

    ### IOS开发入门详解 #### 一、iOS介绍 iOS 是苹果公司专为移动设备开发的操作系统,主要应用于 iPhone、iPod touch、iPad 和 Apple TV 等设备上。该操作系统基于 Apple Darwin,Darwin 本质上属于类 Unix 系统,...

    iOS Runtime详解(新手也看得懂)

    Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。 Objective-C 是一个动态...

    iOS runtime forwardInvocation详解及整理

    在iOS开发中,Objective-C runtime 是一个强大的框架,它允许我们在运行时动态地修改和操作对象的方法。`forwardInvocation:`是Objective-C runtime 提供的一种消息转发机制,它为我们提供了处理未知或未实现方法的...

Global site tag (gtag.js) - Google Analytics