Objective-C 2.0从2006年正式发布至今已经有10年了。Apple在此期间也不断地为其注入新的语法特性,比如Blocks、NSNumber literal、NSArray literal、NSDictionary literal、@() compund literal、Object subscripting、instancetype、lightweight generics等等。然而,其核心语法变化不大。

本人从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:@"%d", 100] autorelease];

上述代码嵌套了多层方法调用。但是对于程序员来说,写代码时都是按照线性思维进行的。也就是说,我一开始总是会想到先分配一个NSString对象,然后调用init初始化方法对其初始化,最后想到用autorelease方法来省去后面手工release的麻烦。而用[]机制,那么你每写好一个方法调用就需要回过去加[,这显然十分麻烦~

而本人这里所提供的改进意见是,使用 . 这个操作符(operator)来表示消息发送机制:

object . message (parameter-list)

上述代码可写为:

NSString *str = NSString.alloc().initWithFormat(@"%d", ).autorelease();

整个调用过程就显得更为清晰。而之前方法的声明与定义形式依旧不变,所以,如果方法里有多于1个形参,那么后续形参也需要带有自己的标签。比如:

    NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *path = [[fileMgr URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:NULL] path];
NSLog(@"The path is: %@", path); // 可写为以下形式:
NSFileManager *fileMgr = NSFileManager.defaultManager();
NSString *path = fileMgr.URLForDirectory(NSCachesDirectory, inDomain:NSUserDomainMask, appropriateForURL:nil, create:NO, error:NULL).path();

这看上去与Swift的方法调用差不多。

那么现在估计各位可能会有这么一个问题,使用了点语法作为消息发送(方法调用)之后,如何与property加以区分呢?

如果 . 操作符后面的标识符后面没有圆括号,说明使用的是property,如果带有括号,说明使用的是方法。比如:

NSUInteger len = @"Hello".length;    // 这里使用的是property

NSUInteger len = @"Hello".length();  // 这里显式地调用property的getter方法,相当于[@"Hello" length]

此外,由于Objective-C已经有了强大灵活的消息机制,所以它不需要再包含类似于C++中指向类成员函数指针这种特性,所以用点语法其实完全能行得通,而且也能与现有的C/C++的语法完全兼容。

2、类静态成员变量与类property:

我们知道,现在Objective-C类有类方法,但是木有类属性。其实,加入类成员变量和类属性不仅能使得Objective-C在语法体系上更加完备,而且也能提供更好的模块化编程形式。

类静态成员变量非常简单,只需要在@interface或@implementation的 { }作用域中使用static存储类说明符即可。比如:

@interface MyObject : NSObject
{
@public int n; // 对象成员变量 static int s; // 类静态成员变量
} @end

对类静态成员变量的访问也是通过 -> 操作符。比如:

MyObject *obj = MyObject().alloc().init();
int a = obj->n; // 访问对象成员
a += MyObject->s; // 访问类静态成员

而要定义类property的方法也同样简单,跟定义对象property一样,只是在前面添加 + 号。比如:

@interface MyObject : NSObject
{
@public int n; // 对象成员变量 static int s; // 类静态成员变量
} - @property (nonatomic, retain) NSString *objStr; // 定义了对象property
+ @property (nonatomic, retain) NSString *classStr; // 定义了类property @end

在synthesize的时候,对象property与类property需要分开。在做类property的synthesize的时候,前面也是加 + 号进行指定。比如:

@implementation MyObject

- @synthesize objStr;      // 综合对象property
+ @synthesize classStr; // 综合类property @end

这么做可以使得对象property与类property可以有完全相同的属性名。上述代码片段中,@synthesize objStr相当于编译器给MyObject类定义了 - (void)setObjStr:(NSString*, retain)str与- (NSString*)objStr这一对setter和getter方法,同时为MyObject增添了私有对象成员变量NSString*objStr。而@synthesize classStr相当于编译器给MyObject类自动定义了+ (void)setClassStr:(NSString*, retain)str与+ (NSString*)classStr这一对setter和getter方法,同时为MyObject增添了私有类静态成员变量NSString *classStr。

这里要再提的一点是,引入了类静态property之后,实例property可以在@property前加 - 号,@synthesize之前也可加 - 号。否则对于某些星座的人来说,看代码没对齐难受得慌,呼哈哈~如果 - 缺省,那么默认为实例property。

下面我简单介绍一下类静态成员变量与类属性的实现方式。因为Objective-C完全基于C语言,可以看作是C语言的一套马甲~所以我们完全可以把Objective-C代码的编译过程理解为先将源代码完全翻译成C代码,然后再对C代码进行编译。所以,这里对于新增语法的特性也不能违背此重要原则。对于Objective-C编译器如果遇到了类静态成员以及/或类属性,那么可以把此类定义为一个全局外部对象,对象名可以诸如_objc_class_<class name>_<category name>。然后,runtime库也需要增加对类属性的访问接口。

3、带方法形式说明的SEL类型

我们在使用Objective-C时,常常会发现SEL类型参数没有具体说明,此时我们就可能需要进一步查找各种文档资料确定这个selector传多少个参数,每个参数需要是什么类型的。在Objective-C 3.0中,我们将给SEL加上方法类型说明,包括方法的返回类型以及参数类型。比如,我们常用的用于定时器消息回调的参数可以写作为:

SEL<void* (NSTimer*)>

这里之所以使用<>是因为,一来这样可以跟函数参数的圆括号进行明显区分开;二来这种表达更类似protocol,表示这个selector实参需要满足<>内的返回类型与参数列表形式。

以上就是我目前所想到的内容。各位感觉何如呢?呼呼~

漫谈Objective-C在语法上的改进的更多相关文章

  1. C++与Java语法上的不同

    最近学习算法和刷题基本都是用C++写的程序,在这个过程中,发现C++和Java在语法上有很多相同点,但也有很多不同点,而这些不同点对于已经掌握Java的程序员来说,理解C++代码可能会有些吃力甚至困难 ...

  2. 语法上的小trick

    语法上的小trick 构造函数 虽然不写构造函数也是可以的,但是可能会开翻车,所以还是写上吧.: 提供三种写法: ​ 使用的时候只用: 注意,这里的A[i]=gg(3,3,3)的"gg&qu ...

  3. swift 2.2 语法 (上)

    前言: 1.此文中的语法会根据Swift的升级变动而更新. 2.如果需要请移步 -> swift2.2 语法(中).swift 2.2语法(下) Swift与OC中常见的区别 导入框架 OC: ...

  4. 12天搞定Python,基础语法(上)

    不知你是否见过建楼房的过程,没有的话,找个时间去瞧一瞧,看一看.看过之后,你就会明白.建楼房,只有打好地基之后,才能在砌墙,建的楼层越高,打的地基就越深. 学编程也一样,要想得心应手的应用,得先打好地 ...

  5. Markdown基础语法(上)

    前言 按照官方文档,和根据自己所用和所理解所写 一.标题语法 一级标题最大,六级标题最小 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标 ...

  6. Java 和C/C++的“语法”上的差异!

    额其实认为语言语法之间是没有可比性的! 但是因为额曾经学过C/C++,而今又学Java,有赵本山说的话:“知识都学杂了!”,所以我个人总结一下,望提醒自己! Java C++ double 要用%f: ...

  7. 吾八哥学Python(三):了解Python基础语法(上)

    学习一门开发语言首先当然是要熟悉它的语法了,Python的语法还算是比较简单的,这里从基础的开始了解一下. 标识符1.第一个字符必须是字母表中字母或下划线'_'.2.标识符的其他的部分有字母.数字和下 ...

  8. 第2章 Java基本语法(上): 变量与运算符

    2-1 关键字与保留字 关键字(keyword) 保留字(reserved word) 2-2 标识符(Identifier) 案例 class Test{ public static void ma ...

  9. Java基础语法(上)

    Java编译报错出现非法字符,原因是存在中文字符. Java关键字的字母都是小写. Java是一种强类型语言,针对每一种数据都给出了明确的数据类型. 数据类型分类: A:基本数据类型 B:引用数据类型 ...

随机推荐

  1. springboot 部署到tomcat,获取根路径问题。空格变为%20

    String path = ResourceUtils.getURL("classpath:").getPath()+"static/upload"; Syst ...

  2. redis缓存击穿和缓存雪崩

    工作中经常会用到redis来做缓存,以防止后台db挂掉.但是db数据一般都在10T以上,不可能把mysql中的数据全部放入redis中,所以一般是将一些热key放入redis中. 缓存击穿 一个请求先 ...

  3. django的信号应用

    问题? 比如说我们在操作数据库的时候,要在插入数据之前写入日志,插入完成之后也写入日志,那这个就会用到我们今天的django信号. 也许你会想到,函数装饰器的有这样的功能.其实不用那个,django的 ...

  4. java - day008 - 接口,内部类

    接口 作用: 结构设计工具,用来解耦合,需要有子类,隔离具体实现 接口是一个极端的抽象类 用 interface 代替 class 用 implements 代替 extends // 接口中所有东西 ...

  5. Python查看模块函数,查看函数方法的详细信息

    Python查看方法的详情 1.通用的帮助函数help() 使用help()函数来查看函数的帮助信息. 如: import requests help(requests) 会有类似如下输出: 2.查询 ...

  6. 如何利用while语句打印“九九乘法口诀表”

    需求:输出九九乘法表 plus.py代码如下: i=1 j=1 while i<=9: j=1 while j<=i: print(j,'*',i,'=',str(i*j)+' ',end ...

  7. Ubuntu系统---终端下用g++进行c++项目

    Ubuntu系统---终端下用g++进行c++项目 目录 一.编译工具(g++/gcc)和编辑工具(vim/gedit)二.C语言 的编译与运行三.C++语言 的编译与运行四.gcc/g++的详细过程 ...

  8. 一篇文章教你如何部署.NET Core WPF应用,你还在等什么?

    DevExpress广泛应用于ECM企业内容管理. 成本管控.进程监督.生产调度,在企业/政务信息化管理中占据一席重要之地.通过DevExpress WPF Controls,您能创建有着强大互动功能 ...

  9. jface viewer 全选

    viewer.setSelection(new StructuredSelection(((List)viewer.getInput()))); StructuredSelection有多个构造方法, ...

  10. J-Link OB F103 固件提取及维修

    焊接心得挺不错的,可以学习到了 事情起因 某日在调试stm32的时候,错将5v接入3.3v电源输入,开发板烧掉.而且因为jlink没拔掉,也一同阵亡了.光烧了个芯片把整个板换掉太亏,遂打算动手修复. ...