之前寫過一篇attribute((constructor))用法探究,當時是在看代碼的時候,對它產(chǎn)生了偶遇.而這幾天,越發(fā)發(fā)現(xiàn)這個__attribute__
的強大.作為一個iOS開發(fā)者,我試著總結(jié)了一下這個在我們?nèi)粘i_發(fā)中的應(yīng)用.
從 __Nonull說起
蘋果在Xcode6.3中引入了這個特性, 目的在于為Swift混編時,讓編譯器知道這個Object-C對象是不是可選的.使用方法如下:
-(void)openPath:(NSString * _Nonnull)path;
今天在llvm的文檔中,發(fā)現(xiàn)了一段這樣的描述:
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
這個屬性表示函數(shù)的參數(shù)不能為空,并且這個屬性有幾種不同的使用方式,最基本的用法就是用來修飾函數(shù)(或者OC的方法),使用一個用逗號分隔的參數(shù)表來表明函數(shù)或者方法的那個哪個參數(shù)非空.
還是代碼比較明顯:
-(void)openFile:(NSString*)file __attribute__((nonnull(1)));
當我們這么使用時候:
[self openFile:nil];
就會得到這么一個警告:
幾個注意點:
- nonull的參數(shù)從1開始
- OC的隱含參數(shù)
self
和_cmd
不計入?yún)?shù)范圍
_Nonnull
和_Nullable
在文檔中也有說明:
_Nonnull
修飾指針類型,表示這個指針類型不會把null
當做有意義的參數(shù),用法如下:
int fetch(int * _Nonnull ptr);
_Nullable
修飾指針類型,表示這個指針類型可以是null
的,用法如下:
int fetch_or_zero(int * _Nullable ptr);
注意:它們只能修飾指針類型的參數(shù).
RAC中的 @onExit
用過RAC的應(yīng)該對這個關(guān)鍵字不陌生,它實現(xiàn)了,當一個變量作用域結(jié)束時,調(diào)用指定的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 {}
.
言歸正傳,我們關(guān)注這個部分:
__attribute__((cleanup(rac_executeCleanupBlock), unused))
先說簡單的,unused
表示函數(shù)或者變量可能不用,防止編譯器產(chǎn)生警告.
而這個__attribute__((cleanup(...)))
用來修飾變量,當變量的作用域結(jié)束的時候,就調(diào)用參數(shù).參數(shù)是一個函數(shù),當然,也可以是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
的參數(shù)方法:它的參數(shù)是修飾的變量的地址.所以會用到了*block
和**string
,另外:
對于指向objc對象的指針(id *)落蝙,如果不強制聲明__strong
默認是__autoreleasing
泉懦,造成類型不匹配
參考鏈接: