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. 全文检索引擎在Django中的使用

    Haystack 1.什么是Haystack Haystack是django的开源全文搜索框架(全文检索不同于特定字段的模糊查询,使用全文检索的效率更高 ),该框架支持Solr,Elasticsear ...

  2. JS Array.reverse 将数组元素颠倒顺序

    <pre><script type="text/javascript"> //JS Array.reverse 将数组元素颠倒顺序//在JavaScript ...

  3. 用js刷剑指offer(反转链表)

    题目描述 输入一个链表,反转链表后,输出新链表的表头. 牛客网链接 js代码 /*function ListNode(x){ this.val = x; this.next = null; }*/ f ...

  4. test11111111

    test 博文内容中字符过多,拒绝显示 123123123

  5. windwos服务器 无法与本地电脑进行复制粘贴解决办法

    之前复制粘贴功能可以使用  现在突然间不能使用了 1.打开任务管理器,查看进程,如果有 rdpclip.exe 进程,先关闭该进程2.开始->运行->rdpclip.exe,重新运行此程序 ...

  6. Spring Bean装配(上)

    Bean:在spring的IOC里面,把配置到IOC容器里面的实体或者是对象都称为Bean Bean配置项 Bean的作用域 Bean的生命周期 Bean的自动装配 Resources&Res ...

  7. Python进阶:都说好用的 Python 命令行库click

    click 是一个以尽可能少的代码.以组合的方式创建优美的命令行程序的 Python 包.它有很高的可配置性,同时也能开箱即用. 它旨在让编写命令行工具的过程既快速又有趣,还能防止由于无法实现预期的 ...

  8. Catalan Number-卡特兰数入门

    卡特兰数 首先,我们设f(n)=序列个数为n的出栈序列种数.同时,我们假定,从开始到栈第一次出到空为止,这段过程中第一个出栈的序数是k.特别地,如果栈直到整个过程结束时才空,则k=n. 令h(0)=1 ...

  9. mouseout([[data],fn])

    mouseout([[data],fn]) 概述 当鼠标指针从元素上移开时,发生 mouseout 事件. 该事件大多数时候会与 mouseover 事件一起使用.深圳dd马达 注释:与 mousel ...

  10. this绑定问题

    this是属性和方法“当前”(运行时)所在的对象.this是函数调用时发生的绑定,它的值只取决于调用位置(箭头函数除外). 函数调用的时候会产生一个执行上下文,this是对这个执行上下文的记录. ❌误 ...