<<Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法>>读书笔记之objc_msgSend

<span style="font-size:18px;">1.在Objective-C中,在对象上调用方法叫做"消息传递".</span>
<span style="font-size:18px;">2.在Objective-C中,如果向对象传递消息,那就会使用"动态绑定机制"来决定需要调用的方法.对象在收到消息后,究竟调用哪个方法则完全取决于运行时.</span>
<span style="font-size:18px;">给对象发送一条消息:id resultValue = [someObj messageName:parameter];</span>

这里,someObj是receiver,messageName是selector.  receiver与selector合起来成为消息(message).编译器会将此方法转换成C语言函数:

id resultValue = objc_msgSend(someObj, @selector(messageName), parameter);

(1).objc_msgSend会根据接受者(receiver)和选择子(selector)的类型来调用适当的方法.

(2).objc_msgSend需要再接受者所属的类中搜索其方法列表(list of methods),若找到与选择子名称相符的方法,则跳转并实现.否则将继续寻找.若找不到与之相符的方法,则执行"消息转发操作".

(3).objc_msgSend会将匹配结果缓存在快速映射表中.


3.Objective-C利用了"尾调用优化"技术使得跳转到方法实现这一操作变得简单.

(1.)尾调用(Tail Call):就是指某个函数的最后一步是调用另一个函数

function f(x){
 return g(x);
}

以下两种情况都不属于尾调用。

// 情况一
function f(x){
  let y = g(x);
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;
}


上面代码中情况一是调用函数g之后还有别的操作所以不属于尾调用即使语义完全一样。情况二也属于调用后还有操作即使写在一行内。


(2)尾调用优化

函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方还会形成一个B的调用记录。等到B运行结束将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈以此类推。所有的调用记录就形成一个"调用栈"(call stack)



function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();

// 等同于
function f() {
  return g(3);
}
f();

// 等同于
g(3);

上面代码中如果函数g不是尾调用函数f就需要保存内部变量mn的值、g的调用位置等信息。但由于调用g之后函数f就结束了所以执行到最后一步完全可以删除 f() 的调用记录只保留 g(3)的调用记录。

这就叫做"尾调用优化"(Tail call optimization),即只保留内层函数的调用记录。如果所有函数都是尾调用那么完全可以做到每次执行时调用记录只有一项这将大大节省内存。这就是"尾调用优化"的意义。


总结:

(1).消息由接受者,选择子和参数构成,给某对象发送消息也就相当于在该对象上调用方法.

(2).发给某对象的全部消息都要由"动态消息派发系统"来处理,该系统会查出对应的方法,并执行代码.

参考:http://www.ruanyifeng.com/blog/2015/04/tail-call.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值