Swift 与 Objective-C

Objective-C 的方括号语法为什么长这样?(消息发送的秘密)

开始学习 iOS 后,第一次看到 Objective-C 代码时,很容易感到困惑。

4 分钟阅读
Objective-C 的方括号语法为什么长这样?(消息发送的秘密) 封面图

开始学习 iOS 后,第一次看到 Objective-C 代码时,很容易感到困惑。

因为代码里到处都是方括号 [ ]。看起来像函数调用,但外观和其他语言差别太大了。

难免会留下“为什么要设计成这样?”的疑问。

先说结论,Objective-C 的方括号不是在“调用”函数,而是向对象“发送消息”的语法。只要理解这个概念,原本陌生的方括号就会突然变得容易读懂。

今天就从它的根源开始,轻松讲讲方括号为什么长成这样。😊


先从核心摘要开始

首先,整理一下这篇文章可以学到的内容。

  1. Objective-C 的方括号表示“向对象发送消息”
  2. 这种语法继承自 Smalltalk 语言
  3. 只要了解 [객체 메서드] 这一结构,就能读懂大多数代码
  4. 在内部会转换为名为 objc_msgSend 的函数后执行

理解这四点,今天的目标就全部达成了。


Objective-C 的消息发送语法到底是什么?

在其他语言中调用方法时,通常会这样写。

object.method()

但在 Objective-C 中会这样写。

// dog 向对象发送 bark 消息
[dog bark];

// count 把值作为参数一起发送
[dog barkTimes:3];

虽然外观看起来陌生,但结构很简单。

[받는객체 보낼메시지]

打开方括号,左边放接收消息的对象,右边写要发送的消息。

所以,[dog bark]的意思就是“dog,请 bark”。

我把它理解成不是“函数调用”,而是“和对象说话”,这样就容易多了。

有多个参数时,结构会像这样扩展。

// 消息名称会 setName:age: 分成两部分
[person setName:@"哲洙" age:20];

可以把它理解为每个冒号(:)后面都会跟一个值。


方括号为什么长这样?

Objective-C 的方括号,是将 Smalltalk 的“消息发送”理念融入 C 语言后留下的痕迹。

故事要追溯到 20 世纪 80 年代初。

Objective-C 由 Brad Cox 和 Tom Love 两人创建。

他们想继续使用当时流行的 C 语言,同时加入面向对象的概念。

这种面向对象思想的典范正是 Smalltalk。

Smalltalk 的核心理念是:“一切都是对象,对象之间通过消息进行通信”。

问题在于,必须在不破坏 C 语法的前提下加入消息这一概念。

因此,他们选用了 C 语法中几乎不用的方括号,把其中定义为发送消息的空间。

这样即使和现有 C 代码混用,也能避免冲突并加以区分。

习惯“发送”消息的感觉后,方括号就会变得顺手
习惯“发送”消息的感觉后,方括号就会变得顺手

后来,NeXT 采用了这门语言;Apple 在 1996 年收购 NeXT 后,它成为 Mac 和 iPhone 开发的基础。

我们熟悉的 Cocoa 框架也由此诞生。

一个陌生的方括号背后,竟然承载着如此漫长的历史。


它和点号(.)语法有什么不同?

如今的 Objective-C 代码中也经常能看到点号(.)语法。

比如 dog.name

因此很容易混淆,我把两者的关系整理成了表格。

分类 方括号语法 点号(.)语法
形式 [dog name] dog.name
含义 消息发送 属性访问
出现时期 从早期开始 Objective-C 2.0(2007 年)之后
内部行为 执行方法 实际上转换为方法

有趣的是,点号语法最终也会在内部转换为方括号消息。

也就是说,dog.name执行时做的事情和[dog name]相同。

点号语法只是为了方便阅读而加上的外衣。

所以我建议初学者先理解,本质其实是方括号。


方括号内部到底发生了什么?

让我们再深入一点。

写下 [dog bark] 时,编译器会把它转换为对 objc_msgSend 函数的调用。

// 我们写的代码
[dog bark];

// 在内部大致会转换成这样
objc_msgSend(dog, @selector(bark));

第一个位置放接收消息的对象,第二个位置放要执行的方法名称标签(selector)。

外观看起来不同,最终都会汇聚到同一个地方
外观看起来不同,最终都会汇聚到同一个地方

这种方式很灵活,因为可以在运行时决定要执行哪个方法。

因此,Objective-C 很擅长在运行过程中修改或添加方法等动态功能。

方括号的外表之下,原来隐藏着这样灵活的结构。

用上几天就会顺手的语法
用上几天就会顺手的语法

通过问答做个总结

问:一定要记住方括号吗?

与其死记硬背,只要掌握 [받는객체 보낼메시지] 这一结构,就能自然读懂。

问:我现在使用 Swift,还需要了解吗?

许多旧库和示例代码至今仍使用 Objective-C 编写,所以能够读懂会很有帮助。

问:如果方括号里面还有方括号呢?

这是外层再次接收内层结果的结构。从内向外阅读就能理解。


方括号看起来只是奇怪的规则,但换个角度,把它理解成“和对象说话的语法”,就会亲切得多。

越是陌生的语法,了解它的根源后反而越容易长久记住。

希望这篇文章能成为你进一步了解 Objective-C 的契机。为你加油!🙌

延伸阅读