Objective-C 2.0从2006年正式发布至今已经有8年了。Apple在此期间也不断地为其注入新的语法特性,比如Blocks、NSNumber literal、NSNumber literal、NSArray literal、NSDictionary literal、Object subscripting等等。然而,其核心语法变化不大。
本人从2009年夏季开始接触Objective-C,一开始总是不习惯其[object message]这种语法形式,不过随着Xcode自身智能感知的不断加强,编辑也逐步方便,所以也渐渐地习惯了,呵呵~现在用下来,感觉Objective-C在面向对象编程方面有其独到之处,而且灵活性相当大,编译器负担也很小,增加的仅仅是运行时库。不过相对于Java这种需要虚拟机的运行时来说要小得多。因此,它是对C++与Java的折衷。C++太过依赖编译器,Java的运行时太过庞杂,而且这两种编程语言对于类型的限制太过重,导致原本一些本应该十分灵活强大的语法特性也受到很多制约。所以,本人也时常跟朋友、同事之间开玩笑地说,“用C++来做项目,总是先考虑其各种语法糖以及各种坑,而往往不能开门见山地进行软件设计”。而Java新增的很多语法也是比较鸡肋,比如泛型就是其中之一,还有Java 8所引入的Lambda表达式。这货跟Java 1.4所引入的匿名类对象没太大不同,反而是Method Reference更有用些,呼呼~
当然,Objective-C也不能说完全没有缺陷,下面我就谈谈目前Objective-C比较令人不快的特性以及其改进建议。
1、消息发送机制:
一开始,Brad Cox引入[object message]的机制确实不错,这个对已有的C语言语法没有任何冲突,因此Objective-C至今对于C/C++的兼容性都能做到100%。不过,这种写法对于编写代码来说有个很大的弊端——当嵌套的方法调用过多时,由于需要往前加[,因此,对于使用不带智能感知的编辑器来说就相当讨厌了。比如:
NSString *str = [[[NSString alloc] initWithFormat:@"%zu", [@"Hello" length]] autorelease];
上述代码嵌套了多层方法调用。但是对于程序员来说,写代码时都是按照线性思维进行的。也就是说,我一开始总是会想到先分配一个NSString对象,然后调用init初始化方法对其初始化,最后想到用autorelease方法来省去后面手工release的麻烦。而用[]机制,那么你每写好一个方法调用就需要回过去加[,这显然十分麻烦~
而本人这里所提供的改进意见是,使用 <| 这个token来表示消息发送机制:
object <| (message)
上述代码可写为:
NSString *str = NSString <| (alloc) <| (initWithFormat:@"%d", 100) <| (autorelease);
整个调用过程就显得更为清晰。为何方法调用需要用()包裹?我们就看上述例子,如果没有括号,那么initWithFormat:@"%d", 100 <| autorelease直接就会导致歧义。由于<|的优先级与C语言中的 . 操作符、-> 操作符一样,都是左结合的。因此,如果这里没有括号,加上逗号优先级是最小的,那么词法解析器就会解析为 100 <| autorelease,显然不是我们所想要的。
这里,(message)是一个整体,括号里不能放其它东西,比如:(a++, alloc)这种就是非法表达式。当然,我们可以这么写:
NSUInteger a = 10; a = (a++, @"Hello" <| (length));
这样,就相当于先做a++操作,然后把@"Hello"的长度给a。