天天看點

屬性“__attribute__”在Objective-C中的應用

關于__attribute__,你可能用的不多,但是一定經常見到,在系統的Foundation架構中,__attribute__的使用非常頻繁。首先,__attribute__用于在函數,變量或類型聲明時進行特殊屬性設定的編譯器指令。需要注意,它是一種編譯器指令,這也就表明了使用它我們可以做更進階的檢查與優化功能。

__attribute__根據其修飾的場景不同可以分為3種類型,分别為函數屬性,變量屬性和類型屬性。__attribute__的使用格式如下:

__attribute__((屬性清單))

下面,我們來介紹幾種常用的__attribute__屬性。

1.format

     format用來對格式化字元串的參數使用情況進行檢查,例如在使用NSLog函數進行輸出時,如果我們傳入的可變參數沒有在格式化字元串中使用,編譯器會提示警告,如下:

屬性“__attribute__”在Objective-C中的應用

其實這個提示警告的功能就是借助__attribute__的format屬性實作的,例如我們自定義一個LOG方法使其擁有相同的功能,如下:

void MyLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));

format屬性有3個參數可以設定,其中第一個參數指定要檢查的格式化風格,這裡設定為NSString的格式化風格,第2個參數為格式化字元串參數的位置,從1開始,第3個參數為對應的格式化可變參數的位置。

2.deprecated

     deprecated可以指定被修飾的函數在編譯時産生警告,表示這個函數已經過期,提示開發者謹慎使用,例如:

屬性“__attribute__”在Objective-C中的應用

deprecated屬性也可以添加一個參數來指定要輸出的警告資訊,例如:

屬性“__attribute__”在Objective-C中的應用

3. availability

     這個屬性用來指定接口的可用版本,例如指定可用的平台,接口引入的版本,廢棄的版本,不可用的版本以及提示資訊等,示例如下:

屬性“__attribute__”在Objective-C中的應用

其中,第1個參數指定API可用的平台,可選則為macos或ios,introduced參數設定API引入的系統版本,deprecated參數設定API廢棄的版本,obsoleted參數用來設定API不可使用的版本。與availability屬性相似,還有一個unavailabel屬性可用,這個屬性直接将某個API标記為不可用,例如:

屬性“__attribute__”在Objective-C中的應用

4. nonnull

     nonnull屬性用來指定某些指針參數不能為空,其内可以傳入一組下标(從1開始),被下标指定的參數不可為空,例如:

屬性“__attribute__”在Objective-C中的應用

5. const

     const屬性是一種編譯優化功能,其可以将某個函數指定為const類型的,這時會将函數的傳回值當做const變量來使用,這時如果沒有使用到傳回值,則函數本身會被優化,避免執行造成額外的性能消耗,例如:

屬性“__attribute__”在Objective-C中的應用

5. cleanup

     cleanup屬性可以實作一個非常強大的功能,它有這樣的一種特點,可以為某個變量指定一個清理函數,當變量離開其作用域的時候,會調用這個清理函數,示例如下:

void clean(int *p) {

   NSLog(@"變量%d被清理", *p);

}

int main(int argc, const char * argv[]) {

   @autoreleasepool {

       int a __attribute__((cleanup(clean))) = 10;

       a  = 20;

   }

   // 離開作用域後 将列印 變量20被清理

   return 0;

需要注意,指定的清理函數會将目前變量的指針作為參數傳入。

6. constructor與destructor

     constructor屬性可以指定函數在main函數執行之前進行調用,與之對應destructor可以指定某個函數在main函數執行結束之後再執行。這是一種非常強大的機制,在實際應用中也非常頻繁,例如對以一個擁有子產品化和路由功能的應用程式,可以通過這種方式來自動化的進行路由注冊(無需手動調用),需要注意,constructor與destructor屬性都可以設定一個優先級參數,優先級高的函數會先執行(0-100的優先級為系統保留),示例如下:

void __attribute__((constructor(101))) func1() {

   NSLog(@"Func1");

void __attribute__((constructor(102))) func2() {

   NSLog(@"Func2");

void __attribute__((destructor(101))) func3() {

   NSLog(@"Func3");

void __attribute__((destructor(102))) func4() {

   NSLog(@"Func4");

// 會依次列印

/*

2020-04-27 16:05:57.270522+0800 TestDemo[33430:13458931] Func1

2020-04-27 16:05:57.271017+0800 TestDemo[33430:13458931] Func2

2020-04-27 16:05:57.271193+0800 TestDemo[33430:13458931] main函數執行

2020-04-27 16:05:57.271273+0800 TestDemo[33430:13458931] Func4

2020-04-27 16:05:57.271316+0800 TestDemo[33430:13458931] Func3

*/

       NSLog(@"main函數執行");

7. objc_subclassing_restricted

     這是Objective-C中常用的一個屬性,有時候,我們定義了一個類,但是不希望再有其他的類繼承于它,即我們要定義的類本身就是一個最終類,不能再被繼承,這是就可以使用這個屬性來修飾,如果有類繼承它會報編譯錯誤,例如:

屬性“__attribute__”在Objective-C中的應用

8. objc_requires_super

     這個屬性用來修飾Objective-C中父類的方法,如果子類進行了重寫,在重寫的方法中沒有調用父類方法,則會進行編譯器提示。在實際程式設計中,很多時候,都是由于子類重寫了父類的方法造成不可預知的問題,通過使用這個屬性可以有效的對開發者進行提示,例如:

屬性“__attribute__”在Objective-C中的應用

9. enable_if

     enable_if提供了一種方式對函數的參數進行校驗,不滿足校驗規則的參數傳遞将在編譯時報錯,使得函數的使用更加安全,例如:

屬性“__attribute__”在Objective-C中的應用

這種編譯時即可對函數參數進行檢查的機制可以避免寫很多運作時的代碼,并且比運作時更高效的規避錯誤。

10. overloadable

     在C語言中,對于相同的函數名,哪怕參數不同,也不能夠重複定義。overliadable屬性可以指定某個函數為可重載,這樣既可定義名字相關參數不同的多個C函數,在調用時,編譯器會根據傳入的參數類型自行判斷具體調用哪個函數,如下:

屬性“__attribute__”在Objective-C中的應用

11. objc_runtime_name

     這是一個很有趣的屬性,其可以運作時改變Objective-C類的類名,但是不會影響其行為。這個屬性通常可以用來做代碼混淆加密,例如:

__attribute__((objc_runtime_name("Some")))

@interface MyObject : NSObject

- (void)myObject:(int)param;

@end

@implementation MyObject

- (void)myObject:(int)param {

   NSLog(@"myObject");

       MyObject *object = [[MyObject alloc] init];

       [object myObject:1];

       NSLog(@"%@", [object class]); // Some

上面的代碼可以很好的運作,但是在列印其類型時卻會列印出一個莫名其妙的Some,需要注意,這個屬性要謹慎使用,其有時候也會非常危險,例如代碼中有做這樣的邏輯就會産生未知的異常,并且很難定位:

[[object className] isEqualToString:@"MyObject"]

除了上面介紹的11中常用的屬性外,可用的屬性還有很多,例如對記憶體的配置設定進行管理的屬性,對初始化方法進行修飾的屬性等,如果有興趣,可以參考如下文檔:

https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html

繼續閱讀