Cocoa中常用的宏定义
Posted 极限水果
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cocoa中常用的宏定义相关的知识,希望对你有一定的参考价值。
我们在 Cocoa 的头文件中常会看到很多宏定义,这里列举几个可能会用到的
NS_AVAILABLE
这个宏定义常用于 API 版本控制,表明函数/属性的使用版本,是否废弃等情况,用法如下:
该方法在 ios 4.0 中引入
+ (void)animateWithDuration:(NSTimeInterval)duration |
该方法在 OS X 10.6 和 iOS 4.0 中引入
- (void)enumerateObjectsUsingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0); |
该方法在 iOS 2.0 中引入在 iOS 6.0 后废弃
- (CGSize)sizeWithFont:(UIFont *)font NS_DEPRECATED_IOS(2_0, 7_0, "Use -sizeWithAttributes:") __TVOS_PROHIBITED; |
该方法在 OS X 10.0 以及 iOS 2.0 引入,在 OS X 10.6 以及 iOS 4.0 后废弃
- (void)removeObjectsFromIndices:(NSUInteger *)indices |
NS_ASSUME_NONNULL
这个属性是 objective-c 3.0中引入的新功能,应该是为了和 swift 做兼容的。因为 swift 是有严格的类型检查的,而在objc一向是动态性很强的语言,所以为了和 swift 做兼容,也引入了一些类型检查相关的属性,这就是其中一个
NS_ASSUME_NONNULL_BEGIN |
使用这个宏把整个类包起来,表明类中所有指针类型都不能显示地置为 nil。
比如
// 这里会给出警告,因为这句代码显示地给 NS_ASSUME_NONNULL_BEGIN 范围内的指针变量赋值为 nil |
可见,NS_ASSUME_NONNULL_BEGIN 只对 显式赋值nil 这种情况编译器会给出警告,所以为了安全起见,代码中依然要对 nil 进行安全判断。
我们通常把这个宏和 nullable 一起使用,比如 AFNetworking 里面的用法
NS_ASSUME_NONNULL_BEGIN |
深入挖掘
我们深入AVAILABLE相关宏内部,发现其使用了 __attribute__
这个编译命令,先看 NS_AVAILABLE 的相关定义
#define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios) |
在 iOS 平台上,CF_AVAILABLE 是这样定义的:
#define CF_AVAILABLE(_mac, _ios) __attribute__((availability(ios,introduced=_ios))) |
下面展开一个方法
+ (void)animateWithDuration:(NSTimeInterval)duration |
展开后
+ (void)animateWithDuration:(NSTimeInterval)duration |
__attribute__
关键字 __attribute__
是一个编译命令,它可以在变量、函数、类型定义时提供一些「属性」,用来增加一些特殊的用法。这篇文章着重介绍下函数属性和变量属性。
函数属性
availability
availability 遍布于众多的 Cocoa 头文件中,提供对「方法调用」的「控制力度」。
上面已写过这里不再赘述。
objc_requires_super (OC 方法)
父类方法声明时,加上:
- (void)fatherMethod __attribute__((objc_requires_super)); |
表示子类重写该方法时,一定要调用 super 函数,否则 xCode 给出警告。
枚举中的 attribute
枚举中可能有些过时的,可以加上 deprecated 来注明,如果用户使用该值,xCode 会给出warning。
typedef NS_ENUM(NSInteger, MyEnum) { |
sentinel (OC 方法、C 函数)
明确变参函数需要 nil 参数作为分界
- (void)endWithNil:(nonnull id)first, ... __attribute__((sentinel)); |
输入代码会自动在后面补一个 nil:
Cocoa中常用的宏定义
warn_unused_result (OC 方法、C 函数)
表示用户一定要使用函数的返回值,否则给出 warning。
比如定义一个函数,并用 warn_unused_result 修饰:
- (int)mustCheckReturnValue __attribute__((warn_unused_result)) { |
如果这样调用,xCode 会给出警告:
[self mustCheckReturnValue]; // Xode 给出警告:Ignoring return value of function declared with warn_unused_result attribute |
提示你,此函数的返回值很重要,你应该加以关注:
NSLog(@"%d", [self mustCheckReturnValue]); // 这里简单打印下,也算是「使用」了返回值:),警告消失 |
nonnull (OC 方法、C 函数)
这个上面同样说过,不再赘述
变量属性
cleanup
表示在变量作用域即将结束时,自动执行一个指定的方法。
举个例子:
// 注意这里的参数必须为「变量的地址」的类型 |
当然,除了纯量类型,cleanup 也可以修饰 OC 对象:
void stringCleanUp(NSString **pString) { |
如果修饰 block:
void blockCleanUp(void (^*block)()) { |
上述代码直接在 blockCleanUp函数里调用这个block,也就是说,某些我们想做的事情,可以不必依赖于 cleanup 函数,而在 block 里面直接写出来就好。比如某些成对的操作:
UIGraphicsBeginImageContext(size); |
可以考虑写成:
UIGraphicsBeginImageContext(size); |
像这样子把成对的操作用这种方式写在一起,防止遗忘,把具体操作移到下方。使用时要一定注意自己的业务场景以及变量的作用域。
objc_runtime_name
修改类在 runtime 中的名称
__attribute__((objc_runtime_name("NewFather"))) |
之后 Father 类在 runtime 中真实名称就变成了 NewFather,通过:
Class class1 = NSClassFromString(@”Father”); 是获取不到类的,必须要通过:
Class class1 = NSClassFromString(@”NewFather”); 才可以。
而且通过:Father *fa = [[Father alloc] init]; 创建一个实例,实例的 isa 为 NewFather。
unused
明确变量即使不使用,也不会产生 warning。平时如果这么定义:
NSInteger i = 10; |
xCode会产生警告,因为 i 以后没有使用过。
这么写可以去除这个警告:
NSInteger i __attribute__((unused)) = 10; |
deprecated
表示变量已经不建议使用。
@property (nonatomic, copy) NSString *str __attribute__ ((deprecated)); |
访问 str 时会给出警告。
__attribute__
到底对谁有用
__attribute__
是在编译阶段起作用的,给函数、变量提供了更多的错误检查、版本控制等能力。其实平时代码中用的并不多,但是如果你在项目中负责公共组件的维护,有些还是很有用的,比如,当接口更新时,用 availability 去标明接口的使用版本、是否废弃;用 objc_requires_super 来要求子类需要调用父类方法等等。
极限水果,专注高端程序员技术与理财人生
以上是关于Cocoa中常用的宏定义的主要内容,如果未能解决你的问题,请参考以下文章