iOS 中常見的宏

判斷系統(tǒng)

  • 描述
    判斷系統(tǒng)
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)

#endif

#if os(Linux)

#endif

targetEnvironment(simulator)

  • 描述
    判斷是否為模擬器
  • 用法
#if targetEnvironment(simulator)
// 模擬器        
#else
        
#endif

__has_include

  • 描述
    此宏傳入一個(gè)你想引入文件的名稱作為參數(shù),如果該文件能夠被引入則返回1,否則返回0。
  • 用法
#if __has_include(<AFNetworking/AFNetworking.h>)
#import <AFNetworking/AFNetworking.h>
#else
#import "AFNetworking.h"
#endif

__func__,__FUNCTION__ ,__PRETTY_FUNCTION__

  • 描述
    GCC實(shí)現(xiàn)了如下的函數(shù)宏
    __func__ C99的標(biāo)準(zhǔn),但是GCC只輸出函數(shù)名稱。
    __FUNCTION____func__
    __PRETTY_FUNCTION__ 非標(biāo)準(zhǔn)宏。這個(gè)宏比 __FUNCTION__ 功能更強(qiáng):
    (1)若用 g++ 編譯 C++ 程序, __FUNCTION__ 只能輸出類的成員函數(shù)名,不會(huì)輸出類名;而 __PRETTY_FUNCTION__ 則會(huì)以 <return-type> <class-name>::<member-function-name>(<parameters-list>)的格式輸出成員函數(shù)的詳悉信息(注: 只會(huì)輸出 parameters-list 的形參類型,而不會(huì)輸出形參名)。
    (2) 若用 gcc 編譯 C 程序,__PRETTY_FUNCTION____FUNCTION__ 的功能相同.

__VA_ARGS__

  • 描述
    C99 編譯器標(biāo)準(zhǔn)允許定義可變參數(shù)宏(variadic macros),這樣就使用擁有可以變化的參數(shù)表的宏。
#define FYFLog(format, ...) NSLog(format, __VA_ARGS__)

缺省號(hào)代表一個(gè)可以變化的參數(shù)表。使用保留名 '__VA_ARGS__' 把參數(shù)傳遞給宏。當(dāng)宏的調(diào)用展開時(shí),實(shí)際的參數(shù)就傳遞給 NSLog() 了。


"##"

  • 描述
    (1)在標(biāo)準(zhǔn) C 里,你不能省略可變參數(shù),但是你卻可以給它傳遞一個(gè)空的參數(shù)。GNU CPP 在這種情況下可以讓你完全的忽略可變參數(shù)。在上面的例子中,編譯器仍然會(huì)有問題( complain ),因?yàn)楹暾归_后,里面的字符串后面會(huì)有個(gè)多余的逗號(hào)。
    為了解決這個(gè)問題, CPP 使用一個(gè)特殊的‘ ## ’操作。書寫格式為:
#define FYFLog(format, ...) NSLog(format, ##__VA_ARGS__)

這里,如果可變參數(shù)被忽略或?yàn)榭眨?## ’操作將使預(yù)處理器( preprocessor )去除掉它前面的那個(gè)逗號(hào)。如果你在宏調(diào)用時(shí),確實(shí)提供了一些可變參數(shù), GNU CPP 也會(huì)工作正常,它會(huì)把這些可變參數(shù)放到逗號(hào)的后面。
(2)##還可以起到連接的作用

#define FYFName(Item) Item##Name
NSString *numName;
NSLog(@"%@", FYFName(num));

這里將會(huì)輸出 numName 的數(shù)據(jù).


__LINE__

  • 描述:在源代碼中插入當(dāng)前源代碼行號(hào)
  • 用法:
#ifdef DEBUG
#define FYFLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define FYFLog(...)
#endif

__FILE__

  • 描述:在源文件中插入當(dāng)前源文件名
  • 用法:
NSLog(@"__FILE__ %s", __FILE__);

__DATE__

  • 描述:在源文件中插入當(dāng)前的編譯日期

__TIME__

  • 描述 在源文件中插入當(dāng)前編譯時(shí)間

__STDC__

  • 描述:當(dāng)要求程序嚴(yán)格遵循ANSI C標(biāo)準(zhǔn)時(shí)該標(biāo)識(shí)被賦值為1

__cplusplus

  • 描述:當(dāng)編寫 C++ 程序時(shí)該標(biāo)識(shí)符被定義

NS_ASSUME_NONNULL_BEGIN 與 NS_ASSUME_NONNULL_END

  • 描述:

在swift中,可以使用 !? 來表示一個(gè)對(duì)象是 optional,還是 non-optional,如 view?view! 。而在 Objective-C 中則沒有這一區(qū)分,view 即可表示這個(gè)對(duì)象是 optional,也可表示是non-optioanl。這樣就會(huì)造成一個(gè)問題:在 Swift 與 Objective-C 混編時(shí),Swift 編譯器并不知道一個(gè) Objective-C 對(duì)象到底是 optional 還是 non-optional,因此這種情況下編譯器會(huì)隱式地將 Objective-C 的對(duì)象當(dāng)成是non-optional

為了解決這個(gè)問題,蘋果在 Xcode 6.3 引入了一個(gè) Objective-C 的新特性:nullability annotations。這一新特性的核心是兩個(gè)新的類型注釋:__nullable__nonnull。從字面上我們可以猜到,__nullable 表示對(duì)象可以是 NULLnil,而 __nonnull 表示對(duì)象不應(yīng)該為空。當(dāng)我們不遵循這一規(guī)則時(shí),編譯器就會(huì)給出警告。

事實(shí)上,在任何可以使用 const 關(guān)鍵字的地方都可以使用 __nullable__nonnull,不過這兩個(gè)關(guān)鍵字僅限于使用在指針類型上。而在方法的聲明中,我們還可以使用不帶下劃線的 nullablenonnull

** Nonnull 區(qū)域設(shè)置 (Audited Regions) **
如果需要每個(gè)屬性或每個(gè)方法都去指定 nonnullnullable,是一件非常繁瑣的事。蘋果為了減輕我們的工作量,專門提供了兩個(gè)宏:NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END。在這兩個(gè)宏之間的代碼,所有簡單指針對(duì)象都被假定為 nonnull,因此我們只需要去指定那些 nullable 的指針。
不過,為了安全起見,蘋果還制定了幾條規(guī)則:

  • typedef 定義的類型的 nullability 特性通常依賴于上下文,即使是在 Audited Regions 中,也不能假定它為 nonnull
  • 復(fù)雜的指針類型(如 id *)必須顯示去指定是 nonnull 還是 nullable。例如,指定一個(gè)指向 nullable 對(duì)象的 nonnull 指針,可以使用 __nullable id * __nonnull
  • 我們經(jīng)常使用的 NSError ** 通常是被假定為一個(gè)指向 nullable NSError 對(duì)象的 nullable 指針。

__IPHONE_OS_VERSION_MAX_ALLOWED 與 __IPHONE_OS_VERSION_MIN_REQUIRED

  • 描述:
    這兩個(gè)宏定義(預(yù)編譯宏),
    __IPHONE_OS_VERSION_MAX_ALLOWED 滿足要求的系統(tǒng)最高版本(可以理解為當(dāng)前設(shè)備的系統(tǒng)版本)
    __IPHONE_OS_VERSION_MIN_REQUIRED 滿足要求的系統(tǒng)最低版本(也就是iOS Deployment Target選擇的版本)

  • 用法:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
// 系統(tǒng)版本在iOS7.0及以上則編譯此部分代碼
#else
// 如果低于iOS7.0則編譯此部分代碼
#endif

NS_EXTENSION_UNAVAILABLE_IOS

  • 描述:
    標(biāo)記 iOS 插件不能使用這些 API,后面有一個(gè)參數(shù),可以作為提示(比如提示應(yīng)該用什么 API 替換)。
  • 用法:
// 示例 1:
NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.")
@interface AFNetworkActivityIndicatorManager : NSObject
@end

// 示例 2:
+ (UIApplication *)sharedApplication NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.");

參考:

一九八網(wǎng)絡(luò)科技V客學(xué)院
Nullability and Objective-C

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容