(点击上方公众号,可快速关注)
来源:伯乐在线 - 酷酷的哀殿
链接:http://ios.jobbole.com/89315/
点击 → 申请加入伯乐在线专栏作者
因为作者的疏忽,之前的 GCD源码分析之base.h 一文中,遗漏了一个知识点。今天特地更新了原文并单发一篇文章讲解,希望能够和更多的开发者一起分享知识。
sentinel
sentinel 的中文翻译是哨兵。
经常接触底层库开发的程序员可能会经常遇到它,在计算机的世界中,它是一个表示程序开始或结束的符号(常见的值为 NULL)。
iOS 开发者可以通过在 objc4-NSObject.mm 页面中搜索
POOL_SENTINEL
来查看其用法。POOL_SENTINEL
的作用是用来当做不同autorelease pool
的边界。
当 attribute 和 sentinel 放到一起时,它可以起到通知编译器:当接收可变参数时,NULL 所在的位置。
下面,我们通过几个具体的例子来查看它的用法。
上面的例子中,所有的函数参数都分为两部分:指针 + 可变参数列表。
__attribute__ ((sentinel)) __attribute__ ((sentinel(0))) __attribute__ ((sentinel(0, 0))) 三种写法的作用是一样的,它们表示可变参数中,从后朝前数,第0个参数为 NULL。
__attribute__ ((sentinel(2))) 和 __attribute__ ((sentinel(2, 0))) 的作用是一样的,它们表示可变参数中,从后朝前数,第2个参数为 NULL
小结1:__attribute__ ((sentinel(n))) 限制了可变参数的参数数量至少为 n+1
细心的读者已经注意到,最后一个函数的描述符的写法是 __attribute__ ((sentinel(2, 1)));。它和上一个描述符的区别是由 0 变为了 1。调用该函数时,可变参数列表部分没有 NULL。
实际上,在 sentinel 的相关用法中,开发者可以通过设置第二个参数为 1 的方式告诉编译器,可变参数列表前面的参数也当做可变参数列表的一部分。这也意味着,当前面的参数为 NULL 时,即使参数个数为 2,没有满足 n+1,也是合法的行为。
小结2:__attribute__ ((sentinel(n,1))) 意味着可变参数的参数数量在前一个参数为 NULL 的情况下,可以为 n 个。
示例如下代码如下:
修饰符指定了从后往前数第三个为 NULL,如果不满足这个规则,编译器会产生警告️。
sentinel(n, 0) 和 sentinel(n, 1)
sentinel(n, 0) 和 sentinel(n, 1) 之间的区别是处理变长参数前面最后一个被命名参数的方式不同。比如,下面示例中的 void* a。sentinel(0, 0) 意味着该参数 不被包含到空值中断列表中。sentinel(0,1) 意味着该参数被包含到空值中断列表中。
在下面的示例中,第二个函数使用 sentinel(0, 1) 进行修饰,用容易理解的读法就是,可变列表中,最后一个 NULL 后面有 0 个变量,该 NULL 值可以出现在 void *a 的位置也可以。
而第一个函数使用 sentinel(0, 0) 进行修饰,用容易理解的读法就是, void *a 后面的可变列表中,最后一个 NULL 后面有 0 个变量。因为调用函数时,只传了一个 NULL,参数,该参数只满足了对 void *a 的赋值,却不满足从后往前数第0个为 NULL,所以会产生可变参数不够的警告️。
专栏作者简介 ( )
酷酷的哀殿:常年混迹于创业公司的 iOS 开发者。
打赏支持作者写出更多好文章,谢谢!
关注「 iOS大全 」
看更多精选 iOS 技术文章
↓↓↓