美文网首页
用__Attribute__做点好玩的事情:第一篇

用__Attribute__做点好玩的事情:第一篇

作者: kenny肉桂 | 来源:发表于2016-09-28 17:59 被阅读174次

    之前写过一篇attribute((constructor))用法探究,当时是在看代码的时候,对它产生了偶遇.而这几天,越发发现这个__attribute__的强大.作为一个iOS开发者,我试着总结了一下这个在我们日常开发中的应用.

    从 __Nonull说起

    苹果在Xcode6.3中引入了这个特性, 目的在于为Swift混编时,让编译器知道这个Object-C对象是不是可选的.使用方法如下:

    -(void)openPath:(NSString * _Nonnull)path;
    

    今天在llvm的文档中,发现了一段这样的描述:

    
    The nonnull attribute indicates that some function parameters must not be null, and can be used in several different ways. It’s original usage (from GCC) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. 
    
    

    大概意思是:
    nonnull这个属性表示函数的参数不能为空,并且这个属性有几种不同的使用方式,最基本的用法就是用来修饰函数(或者OC的方法),使用一个用逗号分隔的参数表来表明函数或者方法的那个哪个参数非空.

    还是代码比较明显:

    -(void)openFile:(NSString*)file __attribute__((nonnull(1)));
    

    当我们这么使用时候:

     [self openFile:nil];
    

    就会得到这么一个警告:


    20160928147504628663285.jpg

    几个注意点:

    • nonull的参数从1开始
    • OC的隐含参数self_cmd不计入参数范围

    _Nonnull_Nullable在文档中也有说明:

    _Nonnull修饰指针类型,表示这个指针类型不会把null当做有意义的参数,用法如下:

    int fetch(int * _Nonnull ptr);
    

    _Nullable修饰指针类型,表示这个指针类型可以是null的,用法如下:

    int fetch_or_zero(int * _Nullable ptr);
    

    注意:它们只能修饰指针类型的参数.

    RAC中的 @onExit

    用过RAC的应该对这个关键字不陌生,它实现了,当一个变量作用域结束时,调用指定的block,查看这个宏的定义:

    #define onExit \
        rac_keywordify \
        __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^
    

    这个rac_keywordfiy的定义如下:

    #if DEBUG
    #define rac_keywordify autoreleasepool {}
    #else
    #define rac_keywordify try {} @catch (...) {}
    #endif
    

    这也是为什么onExit使用的时候,前面需要添加一个@,因为只有这样才能凑成完整的@autoreleasepool或者@try {}.
    言归正传,我们关注这个部分:

    __attribute__((cleanup(rac_executeCleanupBlock), unused))
    

    先说简单的,unused表示函数或者变量可能不用,防止编译器产生警告.
    而这个__attribute__((cleanup(...)))用来修饰变量,当变量的作用域结束的时候,就调用参数.参数是一个函数,当然,也可以是block,RAC里面就是这么干的.用代码来说明:

    static void stringCleanUp(__strong NSString **string) {
        NSLog(@"%@", *string);
    }
    
    static void cleanupBlock(__strong void(^*block)(void)) {
        (*block)();
    };
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        __strong NSString * myname  __attribute__((cleanup(stringCleanUp), unused)) = @"kenny";
        
        __strong void(^block)(void) __attribute__((cleanup(cleanupBlock), unused)) = ^{
            NSLog(@"gonna released");
        };
    }
    

    需要注意的是cleanup的参数方法:它的参数是修饰的变量的地址.所以会用到了*block**string,另外:

    对于指向objc对象的指针(id *),如果不强制声明__strong默认是__autoreleasing,造成类型不匹配

    参考链接:

    Common-Variable-Attributes

    http://blog.sunnyxx.com/2014/09/15/objc-attribute-cleanup/

    相关文章

      网友评论

          本文标题:用__Attribute__做点好玩的事情:第一篇

          本文链接:https://www.haomeiwen.com/subject/vufkyttx.html