本文是自《Clang Language Extensions》 中选取部分与Objective-C相关的内容翻译,由于作者水平有限,如存在理解错误或翻译不到位的地方,还请指正!
特性检查宏(Feature Checking Macros)
__has_builtin
此函数类型的宏传递一个函数名作为参数来判断该函数是否为内置函数。
|
|
__has_feature
& __has_extension
这两个函数类型的宏传递一个特性的名称作为参数,如果该特性同时被Clang和当前语言的标准所支持,__has_feature
返回1,否则返回0。如果该特性被Clang和当前语言(不管是该语言的扩展还是标准)所支持,__has_extension
返回1,否则返回0。
|
|
出于向后兼容的考虑,__has_feature
也可以用来检查非标准语法特性,如:不是以c_
、cxx_
、objc_
等为前缀的特性。所以用__has_feature(blocks)
来检查是否支持block也是可以的。如果设置-pedantic-errors
选项,__has_extension
和__has_feature
作用就是一样的。
__has_attribute
此宏传递一个属性名称用于检查该属性是否被支持。
|
传入的属性名也可以采用前后加__
(下划线)的命名方式来防止命名冲突,所以这里__always_inline__
和always_inline
是等价的。
文件引入检查宏(Include File Checking Macros)
并不是所有的系统都一定包含你所需要引入的文件,所以你可以使用__has_include
和__has_include_next
宏在你#include
之前检查你所需要引入的文件在当前系统是否存在。
__has_include
此宏传入一个你想引入文件的名称作为参数,如果该文件能够被引入则返回1,否则返回0。
|
|
为了兼容非clang编译器,你可以这样写:
|
|
__has_include_next
此宏与__has_include
功能相似,只不过会判断引入包含该文件的后面一个路径下的文件 是否可引入。
|
|
__has_include_next
和GNU扩展语句#include_next
一样,只能在头文件中使用,如果在其他的位置使用会引起警告。
__has_warning
此宏传入一个字符串作为参数,该字符串表示一种警告类型,如果该警告有效返回true。
|
|
内置宏(Builtin Macros)
__BASE_FILE__
返回当前文件的路径。
__COUNTER__
计数器,初始值为0,每次使用__COUNTER__
时都会自动+1。(以文件为计数单元,即不同文件中的__COUNTER__
值是独立计数的)
__INCLUDE_LEVEL__
当前文件被引用的深度,main文件时该值为0。
__TIMESTAMP__
返回当前文件最后一次修改的时间戳。
__clang__
布尔值,返回当前编译器是否支持clang。
__clang_major__
返回当前Clang的主版本号(如version4.6.3中的4)。
__clang_minor__
返回当前Clang的次版本号(如version4.6.3中的6)。
__clang_patchlevel__
返回当前Clang的补丁版本号(如version4.6.3中的3)。
__clang_version__
返回当前Clang的完整的版本号。
|
|
除了以上几个宏之外,还有两个是我们经常会用到了
__FUNCTION__
和__LINE__
,分别返回当前代码段所在的函数名和在当前文件中的行数,这个在打印log时比较有用。
带deprecated和unavailable属性的方法
方法或属性可以加上带deprecated
或unavilable
等属性来表示状态。如:
|
|
如果一个方法被标记为deprecated
,在使用时会有警告,如果是unavilable
则会报错。
在iOS和OS X中,苹果也是使用该方法
__attribute__
进行API版本控制,只不过通常使用availability
属性。
带属性的枚举类型(Attributes on Enumerators)
Clang允许给枚举值添加属性来标记某些枚举项是否可选。如:
|
|
在iOS7 SDK中UIStatusBarStyle的定义如下:
|
|
其中 NS_ENUM_AVAILABLE_IOS
和 NS_ENUM_DEPRECATED_IOS
本质上也是使用的__attribute__()
。
availability属性
Clang提供了availability
属性来描述申明对象的生命周期,如:
|
|
表明函数f在iOS4.0时被引入,在6.0是就不推荐使用,到iOS7.0就彻底废弃。
在方法重载的时候,子类的方法可以比父类的方法申明更大的有效范围:
|
|
Objective-C相关特性
相关返回类型(related result types)
按照Cocoa编码的惯例,Objective-C方法以一些关键字(如init
,alloc
等)开头通常会返回一个当前类(Class)的实例对象,这些方法就具有相关返回类型,也就是一个方法返回一个与调用对象同类型的对象。
|
|
通常的初始化方式为:
|
|
表达式[NSArray alloc]
返回的是NSArray*
类型,因为alloc
方法是一个隐性的相关返回类型(related result type)。同样[[NSArray alloc] init]
也是一个NSArray*
类型因为init
也是一个相关返回类型。如果alloc
和init
都不是相关返回类型,他们返回的就和申明的一样是id
类型。
一个具有相关返回类型的方法可以使用instancetype
类型作为返回类型,instancetype
是一个上下文相关的关键字并只能作为Objective-C方法的返回类型。如:
|
|
判断一个方法是否是相关返回类型,可以考虑方法的第一个单词(如:initWithObjects
中的init
),一个相关返回类型方法的返回值的类型和当前类相同,同时:
- 方法的第一个单词是
alloc
或new
的类方法, 或者 - 方法的第一个单词是
autorelease
,init
,retain
或self
的实例方法。
苹果自己从iOS5.0之后就开始在使用instancetype
作为相关返回类型方法的返回类型。
(更多关于instancetype理解可参考:这里 或 这里)
自动引用计数(ARC)
Clang提供了对Objective-C中自动引用计数的支持,这样你就不需要手动调用retain
/release
/autorelease
等方法。与自动引用计数相关有两个宏可用:__has_feature(objc_arc)
用来判断当前环境是否是ARC,__has_feature(objc_arc_weak)
用来判断weak
和__weak
关键字是否可用。
对象字面量和下标
Clang提供了对Objective-C中对象字面量和下标的支持,这些简化了Objective-C编码方式,让程序更简洁。 有几个宏与此相关:__has_feature(objc_array_literals)
判断数组字面量是否支持,__has_feature(objc_dictionary_literals)
判断字典字面量是否支持,__has_feature(objc_subscripting)
判断对象下标是否支持。
Objective-C属性自动合成
Clang支持声明的属性自动合成,也就是只需要申明属性@property NSString *name;
,就会自动为_name生产get/set方法。__has_feature(objc_default_synthesize_properties)
可以检查属性自动合成在当前版本的Clang下是否支持。
objc_method_family
属性
在Objective-C中方法的命名通常代表着方法类型,如以init
开头的方法会被编译器默认为是初始化方法,在编译的时候会将该方法当成初始化方法对待。但是有时候我们并不想以编译器默认的方式给方法取名,或者编译器默认的方法类型与我们自己想表示的有出入。我们就可以使用__attribute__((objc_method_family(X)))
来明确说明该方法的类型,其中X取值为:none
, alloc
, copy
, init
, mutableCopy
, new
。如:
|
|
这样该方法在编译时就不会再被编译器当做为初始化方法了。
Objective-C对象引用属性
在Objective-C中,方法通常是遵循Cocoa Memory Management规范来对参数和返回值进行内存管理的。但是会有特许的情况,所以Clang提供了属性来标识对象引用情况。
使用 ns_returns_retained
, ns_returns_not_retained
, ns_returns_autoreleased
, cf_returns_retained
, cf_returns_not_retained
等属性来说明方法中对返回值引用的情况。
|
|
标记为*_returns_retained
属性的返回的对象引用计数+1了,*_returns_not_retained
属性标记的返回对象引用计数前后没有改变,*_returns_autorelased
属性标记的返回对象引用计数+0,但是会在下一个自动释放池中被释放掉。
使用 ns_cousumed
和cf_consumed
属性来标记在方法中会被+1的参数,ns_consumes_self
属性在Objective-C方法中使用,标记在该方法中self对象的引用计数会被+1。
|
|
你可以使用__has_feature()
方法判断这些属性是否可用。