序
最近查看在網(wǎng)上發(fā)現(xiàn)了個有趣的小玩意__attribute__
, 也就是 Clang Attributes,這是一個編譯器提供的功能聂儒,能夠讓我向編譯器指定一些特殊的功能,比如
- attribute((deprecated)):描述一個方法已經(jīng)廢棄硫痰;
- attribute((objc_requires_super)):描述子類繼承父類的方法時需要調(diào)用 super方法衩婚;
- attribute((cleanup(...))): 描述一個變量在作用域結束時能夠執(zhí)行指定方法;
- ......
Clang 編譯器提供了很多的 __attribute__
功能效斑,下面會介紹一些 Objective-C 中常用的一些功能谅猾。
可以參考相關的文章 NShipster 和 clang-attributes。
__attribute__((deprecated))
描述一個方法鳍悠,表明這是一個被廢棄的方法,如果有地方在調(diào)用坐搔,編譯器會提示一個警告藏研;并且也提供自定義警告信息,格式如下attribute((deprecated("meesage")))
- (void)thisIsADeprecatedMethod __attribute__((deprecated("This is a deprecated message")));
在 Xcode 中概行,我們編寫代碼的時候蠢挡, 編輯器會和 Clang 編譯器的預編譯系統(tǒng)配合,在我們寫代碼的時候凳忙,就在 IDE 中把警告給顯示出來业踏。
__attribute__((objc_boxable))
能夠給 struct 和 union 提供快捷的“包裝”方式。
- CGRect涧卵, CGSize勤家, CGPoint, CGVector 能夠使用框架提供的 boxable 快速“包裝”;
- 自定義 struct 或 union 類型柳恐,也可以添加 attribute((objc_boxable)) 以支持 boxable 快速“包裝”伐脖。
CGPoint point = {1, 2}; // x = 1, y = 2
CGRect rect1 = {1, 2, 3, 4}; // x = 1, y = 2, width = 3, height = 4
CGTriangle triange1 = {1, 2, 3, 4, 5, 6}; // a.x = 1, a.y = 2, b.x = 3, b.y = 4, c.x = 5, c.y = 6
// “包裝”需要的數(shù)據(jù)不夠,不夠的數(shù)據(jù)補0
CGSize size = {1}; // width = 1, height = 0
// “包裝”的 CGRect 中的 CGPoint 需要的數(shù)據(jù)不夠乐设,不夠的數(shù)據(jù)補0
CGRect rect2 = {{1}, {3, 4}}; // x = 1, y = 0, width = 3, height = 4
typedef struct __attribute__((objc_boxable)) {
CGPoint x;
CGPoint y;
CGPoint z;
} CGTriangle;
CGTriangle triange = {1, 2, 3, 4, 5, 6};
// “包裝”的數(shù)據(jù)多了讼庇,最后一條丟掉
CGTriangle triange2 = {1, 2, 3, 4, 5, 6, 7};// a.x = 1, a.y = 2, b.x = 3, b.y = 4, c.x = 5, c.y = 6
這里“包裝”的方式需要注意:
- 可以采用平鋪,如
{1, 2, 3, 4}
近尚,也可以采用嵌套蠕啄,如{ {1, 2}, {3, 4} }
- 如果“包裝”賦值數(shù)據(jù)的個數(shù)比定義的少,則沒有賦值的部分全部為0戈锻,如
CGSize size = {1}; // width = 1, height = 0
- 如果“包裝”賦值數(shù)據(jù)的個數(shù)比定義的多歼跟,則多余的部分丟掉和媳。如
CGTriangle triange2 = {1, 2, 3, 4, 5, 6, 7};// a.x = 1, a.y = 2, b.x = 3, b.y = 4, c.x = 5, c.y = 6
__attribute__((objc_subclassing_restricted))
描述一個類是一個不能被繼承的類。
如果定義一個 Father 類嘹承,并且使用__attribute__((objc_subclassing_restricted))
描述窗价,那么如果一個 Son 類要去繼承于 Father,編輯器會在編譯器的預編譯系統(tǒng)的幫助下叹卷,在 IDE 里面就把錯誤顯示出來撼港。
__attribute__((objc_requires_super))
描述一個子類繼承父類的方法時,需要調(diào)用 super骤竹,否則給出編譯警告帝牡。
如果定義一個 Father 類,里面包含一個 call 方法蒙揣,并且使用__attribute__((objc_requires_super))
描述靶溜,那么如果一個 Son 在調(diào)用 call 的時候,需要顯式的調(diào)用[super call]懒震,如果沒有調(diào)用罩息,那么編輯器會在編譯器的預編譯系統(tǒng)的幫助下,在 IDE 里面就把警告顯示出來个扰。
__attribute__((warn_unused_result))
描述一個方法瓷炮,如果此方法有返回值,但是調(diào)用的地方并未使用返回值递宅,編譯器就會提示一個警告娘香。(編輯器在編譯器的預編譯系統(tǒng)的幫助下,也會在 IDE 中顯示警告)
如下面 Hippo 類的 bite 方法办龄,使用了 __attribute__((warn_unused_result))
進行描述烘绽,在 bite 方法調(diào)用的時候沒有使用返回值,編譯器就就提示了一個警告
__attribute__((cleanup(...)))
修飾一個變量俐填,在它的作用域結束時可以執(zhí)行一個指定的方法安接。
cleanup 是一個用好了就很爽的屬性,詳細內(nèi)容可以查看黑魔法attribute((cleanup))
基本類型變量
如果一個臨時基本類型變量玷禽,在其超出作用域之后赫段,這個變量會直接調(diào)用 cleanup。
對象變量
如果一個臨時變量對象矢赁,在超出其作用域之后糯笙,其臨時變量(變量本身)會被釋放,但是其指向的對象則會根據(jù)他的生命周期來決定是否釋放撩银。也就是說:
- 如果臨時變量對象给涕,沒有被其他對象持有,那么最后其會先調(diào)用 cleanup,然后再調(diào)用 dealloc 方法
- 如果臨時變量對象够庙,被其他對象持有了恭应,那么其只會調(diào)用 cleanup,而 dealloc 是不會被調(diào)用的耘眨。(這是因為臨時變量(變量本身)會被釋放昼榛,但是其指向的對象則會根據(jù)他的生命周期來決定是否釋放)
下面兩個例子可以很好的闡述上面兩個觀點:
而下面的 hippo 對象被當前類給持有了,所以 dealloc 是不會調(diào)用的剔难,只會調(diào)用 cleanup胆屿。