1. 程式人生 > >#if#ifdef#define等巨集定義使用

#if#ifdef#define等巨集定義使用

吐槽:為了提前適配iOS 11,在xcode9 beta版使用過程中,有時候xcode9 beta看圖層一點選就卡死啊,還得強退才行;playground全域性搜尋程式碼有時候失效啊;打包啊….��都得換回xcode8才行。。。
最近碰到了個程式碼執行問題,iOS 11中一些新的API在xdode8中報錯,每次切換xcode時,都得去註釋掉這段程式碼,麻煩死了。怎麼讓一段程式碼在xcode8和9都能順利編譯不報錯,可用巨集做如下設定:

#import "UIScrollView+SFScrollView.h”

@implementation UIScrollView (SFScrollView)

- (void
)neverAdjustmentContentInset{ #ifdef __IPHONE_11_0 if (@available(iOS 11.0, *) ) { self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } #endif } @end //> scrollview的分類中新增的方法,是iOS 11才有的。而巨集__IPHONE_11_0,也是iOS 11才有的,故用#ifdef __IPHONE_11_0即可完美解決,
整理一下,方便使用:

預處理就是在進行編譯的第一遍詞法掃描和語法分析之前所作的工作。說白了,就是對原始檔進行編譯前,先對預處理部分進行處理,然後對處理後的程式碼進行編譯。這樣做的好處是,經過處理後的程式碼,將會變的很精短。

#define  定義一個預處理巨集
#undef   取消巨集的定義
#if      編譯預處理中的條件命令, 相當於C語法中的if語句
#ifdef   判斷某個巨集是否被定義(#define過), 若已定義, 執行隨後的語句
#ifndef  與#ifdef相反, 判斷某個巨集是否未被定義
#elif    若#if, #ifdef, #ifndef或前面的#elif條件不滿足, 則執行#elif之後的語句, 相當於C語法中的else-ifelse    與#if, #ifdef, #ifndef對應, 若這些條件不滿足, 則執行#else之後的語句, 相當於C語法中的else
#endif #if, #ifdef, #ifndef這些條件命令的結束標誌. defined 與#if, #elif配合使用, 判斷某個巨集是否被定義 #pragma 說明編譯器資訊 #warning 顯示編譯警告資訊 #error 顯示編譯錯誤資訊
配置DEBUG巨集:
1.在 "Target > Build Settings > Preprocessor Macros > Debug" 設定"DEBUG=1”。

2.之後在pch或工具類中就可以這麼寫了:
#ifdef DEBUG  
(debug 模式下的配置)
#else  
(release 模式下的配置)
#endif 

#ifdef DEBUG // 除錯狀態, 開啟LOG功能

#define SFString [NSString stringWithFormat:@"%s", __FILE__].lastPathComponent
//打印出所在檔名,所在行,堆疊地址
#define SFLog(...) printf("%s: %p (line = %d): %s\n\n", [SFString UTF8String] , &self, __LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String]);

//#else
//#define SFLog(s, ...) NSLog(@"<%@: %p (line = %d)> %@", self.class, self, __LINE__,[NSString stringWithFormat:(s),##__VA_ARGS__])
//#endif

#else // 釋出狀態, 關閉LOG功能
#define SFLog(s, ...)
#endif

系統巨集介紹:

 __LINE__:巨集在預編譯時會替換成當前的行號

 __FUNCTION__:巨集在預編譯時會替換成當前的函式名稱

__VA_ARGS__:簡單的說,就是將左邊…的內容替換進來

#####詳解#ifdef,#elif,#else,#endif,#if等:

1:
  #ifdef _XXXX  (ifdef 即 if define )
  ...程式段1...
   #elif defined _YYYY
   ...程式段3...(相當於else if)
  #else
  ...程式段2...
  #endif
   
>這表明如果_XXXX已被#define定義過,則對程式段1進行編譯;再如果定義了_YYYY,執行程式段3,否則對程式段2進行編譯。

  例: 
  #define NUM
  .............

  #ifdef NUM
   printf("之前NUM有過定義啦!:) \n");
  #else
   printf("之前NUM沒有過定義!:( \n");
  #endif

>如果程式開頭有#define NUM這行,即NUM有定義,碰到下面#ifdef NUM的時候,當然執行第一個printf。否則第二個printf將被執行。
   我認為,用這種,可以很方便的開啟/關閉整個程式的某項特定功能。
2: 
  #ifndef _XXXX 
  ...程式段1... 
  #else 
  ...程式段2... 
  #endif

>這裡使用了#ifndef,表示的是if not def。和#ifdef相反的狀況(如果沒有定義了識別符號_XXXX,那麼執行程式段1,否則執行程式段2)
3:
  #if 常量 
  ...程式段1...
  #else
  ...程式段2...
  #endif 
  
 >注意:#if後必須跟常量,不能是巨集(因為巨集是在執行階段才有,#if是預編譯階段,找不到巨集);
  如果常量為真(非0,隨便什麼數字,只要不是0),就執行程式段1,否則執行程式段2。
 我認為,這種方法可以將測試程式碼加進來。當需要開啟測試的時候,只要將常量變1就好了。而不要測試的時候,只要將常量變0
常用示例:

1.判斷當前app所支援的最大最小iOS版本

#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED // 當前軟體支援的最大ios版本
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000  
      NSLog(@"當前app支援的最大版本,%d",__IPHONE_OS_VERSION_MAX_ALLOWED);
#else
      NSLog(@"當前app支援的最大版本,%d",__IPHONE_OS_VERSION_MAX_ALLOWED);
#endif
#endif

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED // 當前軟體支援的最小ios版本
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80400
      NSLog(@"當前app支援的最小版本,%d",__IPHONE_OS_VERSION_MIN_REQUIRED);
#else
     NSLog(@"當前app支援的最小版本,%d",__IPHONE_OS_VERSION_MIN_REQUIRED);
#endif
#endif

2.判斷真機/模擬器

#if TARGET_OS_IOS
    NSLog(@"真機測試");
#endif

#if TARGET_IPHONE_SIMULATOR
    NSLog(@"模擬器");
#endif

3.獲得當前裝置的iOS版本

#define kIOSVersion  [[UIDevice currentDevice].systemVersion doubleValue]

4.字型(帶引數的巨集)

#define SFSystemFont(FONTSIZE) [UIFont systemFontOfSize:FONTSIZE]

5.weak strong (RAC寫法)

// weak self
#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif

// strong self
#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif

6.去警告

#define SuppressPerformSelectorLeakWarning(Stuff) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
Stuff; \
_Pragma("clang diagnostic pop") \
} while (0)

7.GCD Block

#define GCDBlock(block) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block)
#define GCDMainBlock(block) dispatch_async(dispatch_get_main_queue(),block)
#define CGDMainBack GCDMainBlock(^(){})

8……很多很多………

原寫於簡書