经过三篇文章的铺垫,这里我们终于要讨论到核心部分,就是关于ObjC的消息机制,但不涉及任何关于runtime的内容。
点语法与中括号
我们知道在ObjC中给对象或者类发消息的标准语法是使用一对中括号:
|
|
这里我们看一下count
、objectAtIndex:
和objectEnumerator
的声明:
|
|
count
作为readonly属性修饰的@property是有getter方法的,所以我们可以通过发送getter消息获取其值,所以对于property来说,中括号和点语法是等效的:
|
|
关于这一点,在Cocoa很多头文件中可以看到这样的声明:
|
|
这里UIView的intrinsicContentSize
属性既有@property声明的形式,也有用实例方法声明的形式,通过UIKIT_DEFINE_AS_PROPERTIES
宏控制。
这里为什么要用两种方式声明我还不是很明白,有知道的朋友可以请加群(100179587)留言,先谢过
然而对于实例方法,两种调用方法则不完全一样,对于objectEnumerator
这种没有参数的方法,是支持点语法的,而objectAtIndex:
则不能用点语法获取。
|
|
仔细思考一下,会发现这个特点很好理解,我们前面说过用构造类似setter和getter的方法模拟@property效果,这里的objectEnumerator
恰好就是一个结构和getter方法相同的方法。所以编译器会无视objectEnumerator
是getter方法还是普通方法,于是我们就可以使用点语法调用它。
类似getter构造,是指没有传递任何参数
然而对于objectAtIndex:
这个传递了一个参数的方法,则不能使用点语法调用。
block的引入
iOS 4.0开始支持block以后,为通过点语法,调用带参数方法带来可行性。代码块(block)既然也是实例,那就可以作为property,也可以作为方法参数传递,Cocoa库中就增加了很多block特性,常见的用法有:
|
|
于是我们可以声明block类型的property,这里还用到第一章里面说的例子:
|
|
上面是我们给NSArray增加的map方法,我们将其写成不带参数的property
|
|
有一丢丢区别,@porperty的写法,xcode可以进行代码补全,而实例方法的写法则不行。
因为block可以传递参数,所以我们将之前例子的中传递的block参数,作为参数写在另一个block里了,这里可能有点绕,理清思路就是
|
|
然后我们实现这个方法:
|
|
于是乎,我们可以这样写代码了:
|
|
通过点语法,调用带参数方法,是不是跟Ruby和Python的写法一样了。
然后我们改造一下第一篇的第一个例子(具体实现留给你们,比上面NSSArray的map要简单),下面是声明:
|
|
于是我们就可以这样来写本地化:
|
|
还没有完
上面说的所有内容,也支持类方法,和类属性。
也许你只用过类方法(+开头的),而没用过类属性,我们声明一个:
|
|
这里用到的是class
关键字进行修饰,于是这个属性的getter方法也变成了类方法,实现如下:
|
|
于是我们就可以用点语法来调用这个修改后的本地化方法:
|
|
其实并没有比NSStringFromCGPoint
简单多少,但是有一点很重要,就是我们将NSStringFromCGPoint()
这个孤零零的C语言函数,变成NSString的类方法,更利于大脑记忆。