编译器属性 __attribute__
用于向编译器描述特殊的标识、检查或优化。
__attribute__
可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。
修饰函数
constructor
使用 constructor
属性修饰函数,使该函数能够在 main()
函数之前执行。
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. //
#import <Foundation/Foundation.h>
__attribute__((constructor)) void testConstructor() { NSLog(@"使用‘constructor’修饰函数,将执行在 ‘main’ 函数之前"); } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); } return 0; }
|
运行结果:
1 2 3
| 2017-04-21 20:14:02.640374+0800 Test__attribute__[1575:31682] 使用‘constructor’修饰函数,将执行在 ‘main’ 函数之前 2017-04-21 20:14:02.640589+0800 Test__attribute__[1575:31682] 'Main' 函数开始执行 Program ended with exit code: 0
|
destructor
使用 destructor
属性修饰函数,使该函数能够在 main()
函数结束后或者 exit()
函数调用后执行。
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. //
#import <Foundation/Foundation.h>
__attribute__((destructor)) void testDestructor() { NSLog(@"使用‘destructor’修饰函数,将执行在 ‘main’ 函数之后"); } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); } return 0; }
|
运行结果:
1 2 3
| 2017-04-21 20:18:35.489606+0800 Test__attribute__[1624:33591] 'Main' 函数开始执行 2017-04-21 20:18:35.489937+0800 Test__attribute__[1624:33591] 使用‘destructor’修饰函数,将执行在 ‘main’ 函数之后 Program ended with exit code: 0
|
__attribute__((constructor))
是如何工作的?详情请看这里
deprecated
使用 deprecated
属性修饰函数,用于警告该函数已经被 废弃
不推荐使用。在 iOS 开发过程中很常见,如果调用某些接口,也会出现类似的警告,如:
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> void deprecatedFunction(void) __attribute__((deprecated("此方法已不推荐使用!"))); int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); deprecatedFunction(); } return 0; }
|
unavailable
使用 unavailable
属性修饰函数,告诉该函数不可用。
PersonObject.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| // // PersonObject.h // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> @interface PersonObject : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) BOOL sex; @property (nonatomic, assign) NSInteger age; - (void)testDeprecated __attribute__((deprecated)); - (void)testUnavailable __attribute__((unavailable)); @end
|
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> #import "PersonObject.h" int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); PersonObject *person = [[PersonObject alloc] init]; [person testDeprecated]; [person testUnavailable]; } return 0; }
|
nonnull
使用 nonnull
属性修饰函数,告诉编译器对函数参数进行 NULL
的检查。
PersonObject.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // // PersonObject.h // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> @interface PersonObject : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) BOOL sex; @property (nonatomic, assign) NSInteger age; - (void)testNonnull1:(id)avg1 avg2:(id)avg2 __attribute__((nonnull)); - (void)testNonnull2:(nonnull id)avg1 avg2:(nonnull id)avg2; @end
|
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> #import "PersonObject.h" int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); PersonObject *person = [[PersonObject alloc] init]; [person testNonnull1:@"" avg2:nil]; [person testNonnull2:nil avg2:@""]; } return 0; }
|
区别:
__attribute__((nonnull))
用于控制连续几个参数不能为空。
nonnull
用于控制单个参数不能为空,控制单个参数时更灵活。
noreturn
定义有返回值的函数时,而实际情况有可能没有返回值,此时编译器会报错。
- 使用
noreturn
属性修饰函数,告诉编译器该函数不会返回(会直接结束)。
- 编译器可以忽略函数调用完成的处理,从而进行相应的优化。
- 多用于强制函数退出、死循环等情况。如系统提供的
abort()
,exit()
函数。
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> void __attribute__((noreturn)) NoReturn1() { printf("'NoReturn1' 函数没有返回,有‘noreturn’修饰,会直接结束!\n"); } void NoReturn2() { printf("'NoReturn2' 函数没有返回,没有‘noreturn’修饰,并不会直接结束!\n"); } int testNoReturn(int state) { if (1 == state) { NoReturn1(); return 1; } else if (2 == state) { NoReturn2(); return 2; } else { return 0; } } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); int ret1 = testNoReturn(1); int ret2 = testNoReturn(2); int ret3 = testNoReturn(0); NSLog(@"ret1 = %d, ret2 = %d, ret3 = %d", ret1, ret2, ret3); } return 0; }
|
运行结果:
1 2 3 4 5
| 2017-04-21 21:31:00.787175+0800 Test__attribute__[3863:120161] 'Main' 函数开始执行 'NoReturn1' 函数没有返回,有‘noreturn’修饰,会直接结束! 'NoReturn2' 函数没有返回,没有‘noreturn’修饰,并不会直接结束! 2017-04-21 21:31:00.787541+0800 Test__attribute__[3863:120161] ret1 = 0, ret2 = 2, ret3 = 0 Program ended with exit code: 0
|
从运行结果 ret1
的值为 0,可以看出函数没有返回值直接退出了。
cleanup
修饰变量
使用 cleanup
属性修饰变量,告诉编译器,在变量的作用域结束时执行指定的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> static void stringCleanUp(NSString **string) { NSLog(@"%@", *string); } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); NSString *string __attribute__((cleanup(stringCleanUp))) = @"Hello World !"; NSLog(@"string = %@", string); NSLog(@"'Main' 函数执行结束"); } return 0; }
|
运行结果:
1 2 3 4 5
| 2017-04-21 21:55:48.283879+0800 Test__attribute__[4556:147371] 'Main' 函数开始执行 2017-04-21 21:55:48.284017+0800 Test__attribute__[4556:147371] string = Hello World ! 2017-04-21 21:55:48.284043+0800 Test__attribute__[4556:147371] 'Main' 函数执行结束 2017-04-21 21:55:48.284060+0800 Test__attribute__[4556:147371] Hello World ! Program ended with exit code: 0
|
修饰 Block
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> static void blockCleanUp(__strong void(^*block)(void)) { (*block)(); } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^{ NSLog(@"Hello World!"); }; block(); NSLog(@"'Main' 函数执行结束"); } return 0; }
|
运行结果:
1 2 3 4 5
| 2017-04-21 22:10:25.290850+0800 Test__attribute__[4901:163032] 'Main' 函数开始执行 2017-04-21 22:10:25.291020+0800 Test__attribute__[4901:163032] Hello World! 2017-04-21 22:10:25.291046+0800 Test__attribute__[4901:163032] 'Main' 函数执行结束 2017-04-21 22:10:25.291057+0800 Test__attribute__[4901:163032] Hello World! Program ended with exit code: 0
|
提示:void(^block)(void) 的指针是 void(^*block)(void)
宏定义 Block
可以将成对出现的代码写在一起,如 NSLock
的使用
1 2
| // 解锁 Macro #define UN_LOCK_BLOCK __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^
|
PersonObject.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // // PersonObject.h // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> @interface PersonObject : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) BOOL sex; @property (nonatomic, assign) NSInteger age; @property (nonatomic, strong) NSLock *lock; @end
|
main.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| // // main.m // Test__attribute__ // // Created by shenyuanluo on 2017/4/21. // Copyright © 2017年 shenyuanluo. All rights reserved. // #import <Foundation/Foundation.h> #import "PersonObject.h" // 解锁 Macro #define UN_LOCK_BLOCK __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^ static void blockCleanUp(__strong void(^*unLockBlock)(void)) { (*unLockBlock)(); } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"'Main' 函数开始执行"); PersonObject *person = [[PersonObject alloc] init]; [person.lock lock]; NSLog(@"进入‘Person’的临界区!"); UN_LOCK_BLOCK { NSLog(@"解锁操作执行!"); [person.lock unlock]; }; /** * 只想相关临界区的操作 */ NSLog(@"'Person'临界区操作代码。。。"); NSLog(@"'Main' 函数执行结束"); } return 0; }
|
运行结果:
1 2 3 4 5 6
| 2017-04-21 22:30:38.815186+0800 Test__attribute__[4987:166666] 'Main' 函数开始执行 2017-04-21 22:30:38.815357+0800 Test__attribute__[4987:166666] 进入‘Person’的临界区! 2017-04-21 22:30:38.815400+0800 Test__attribute__[4987:166666] 'Person'临界区操作代码! 2017-04-21 22:30:38.815417+0800 Test__attribute__[4987:166666] 'Main' 函数执行结束 2017-04-21 22:30:38.815426+0800 Test__attribute__[4987:166666] 解锁操作执行! Program ended with exit code: 0
|
参考资料
- 黑魔法
__attribute__
((cleanup))
- Mattt Thompson 的
__attribute__
- 神奇的attribute
- Objective-C Runtime 运行时之一:类与对象