从iOS点语法引发的一番思考

Starr84

Starr84

发表于 2017-01-09 12:39:56

当我们去点一个属性的时候,我们知道其实是调用了属性的setter或者getter方法。那么,用点调用一个方法会发生什么?

这时候系统并不会崩溃,而只是报一个警告(Property access result unused)。

现在我改成用中括号正常调用方法,可是由于粗心没有在.m中写方法的实现,会发生什么呢?



OC是一门动态编程语言。

调用saySomething这个方法。如果这个方法只是在.h中声明了,而没有在.m中实现。那么我们编译程序不会出现问题(Build Success),只有当运行程序的时候,才会直接崩溃(unrecognized selector sent to instance 0x60000000e8d0)

这是因为在编译阶段,编译器并不知道saySomething要执行那段代码,这个时候[people saySomething]会转换为objc_msgSend(people, "someThing"),就是说给people以selector的形式发送someThing这个消息。当真正运行的时候,才会去people的内存中寻找someThing的地址,这时候找不到才会造成崩溃。

那么,有没有办法说可以不在.m中实现somtThing,而又不让程序崩溃呢?



有!所谓 动态语言,就是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。

想要程序不崩溃,我们有三次机会去拯救它。这个就是消息转发机制的三个步骤

第一步:动态方法解析

下图可以看到,我没有实现saySomething的方法,程序运行成功。实际上是调了doSomething这个方法。

我们这里的saySomething是对象方法,如果是类方法的话,对应的是resolveClassMethod:

第二步:备用接收者

如果我们浪费了第一次机会不用,还有第二次机会拯救工程:把这个消息转给别人,让别人替我处理!

下图可以看到,我没有实现run方法,而是交给了_dog去处理这个消息。在Dog.m中,我实现了的run方法被调用了!

第三步:完整转发消息

如果我们连第二次机会都浪费了,那么还有最后一次机会补救。在完整转发消息这一步中,我们把消息封装到NSInvocation对象中,并把它发给一个能够响应消息的对象。

观察消息转发机制的后两步,其实都已经不是people在处理消息了,而是交给了别人。但是在外面看,我们是调用了[people run] 和 [people eat] 。通过这种方式可以将本来对象A要做的事交给B或C来做。

Github Demo

内容来源:https://segmentfault.com/a/1190000008047643

用户评论
开源开发学习小组列表