Selector 是Objective-C 中所有魔法的开始
Objective-C 对象有哪些method,就是这个对象的Class 的virtual table中,有多少selection/C function pointer 的pair,这个特性造就了在Objective-C 中可以做很多神奇的事情,同时也造成了Objective- C 这门语言的限制。
Objective-C 的神奇之处,就在于,既然对象有哪些method 可以在run time 决定,因此每个对象也都可以在run time 的时候改变。我们可以在不用继承对象的情况下,就增加新的method,通常最常见作法的就是我们接下来要讨论的category,我们也可以随时把既有的selector 指到不同的C function pointer 上,像是把两个selector 所指向的function pointer 交换,这种交换selector 实例的作法叫做method swizzling—我们暂时还不会讨论到这边。
由于一个selector只会指向一个实例,因此, Objective-C不会有C++、 Java、C#等语言当中的overloading。所谓overloading,就是可以容许有多个名称相同,但是参数型别不同的function或method存在,在调用的时候,如果传入了指定型别的参数,就会调用到属于该参数型别的那一组function或method。在Objective-C当中,同一个名称的method,就只会只有一套实作,如果有多个名称相同的method,就会以最后在runtime载入的那一组,代替之前的实作。
Objective-C的virtual table像是一个dictionary,而C++、Java等语言的virtual table则是一个array。在Objective-C中,我们呼叫[someObject doSomthing]
时,我们是在表格中寻找符合"doSomething"这个字串的method,在C++或Java中,我们呼叫someObject.doSomething()
时,在做的事情大概是要求「执行virtual table中的第八个method」这样的事情。
由于每做一次method 的调用,都是在做一次selector/function pointer 的查表,与其他较静态的语言相较,这个查表的动作相当耗时,因此执行效能也比不上C++ 等程式语言。Objective-C 其实是一门相当古老的语言,在1984 年时便问世,但就因为效能问题,在整个80 到90 年代根本乏人问津,直到2008 年iPhone SDK 推出之后才逐渐成为主流语言。
但Objective-C这样做又有另外一项优点:我们的App不需要连结特定版本的runtime与libraries,就算libraries中export出来的function换了位置,只要selector不变,还是可以找到应该要执行的C function,所以旧的App在新版本的操作系统上执行时,新版本操作系统并不需要保留旧版的Libraries,而避免了C++等语言中所谓DLL Hell问题。
到了2014 年,苹果在iOS 与Mac OS X 平台上又推出了新的编程语言Swift,标榜Swift 是比Objective-C 更新、执行性能更好的程序语言,Swift 之所以性能会比Objective-C 好,其中一点,就是因为Swift 又改变了virtual table 的实现,走回像是C++、Java 等语言的virtual table 设计。因为Swift 也有必须连结指定版本runtime 的问题,所以在每个Swift App 的App bundle 中,其实都包了一份Swift runtime。