華山論劍之淺談iOS的宏定義以及內聯函數的使用

你帶著一個故事去聽一首歌感覺會不一樣,你帶著一個故事去找一首歌心情會不一樣。


宏定義的簡介


宏定義是C提供的三種預處理功能的其中一種,這三種預處理包括:宏定義、文件包含、條件編譯.

1. 不帶參數的宏定義:

格式: #define 標識符 字符串

說明:

(1)宏名一般用大寫

(2)使用宏可提高程序的通用性和易讀性,減少不一致性,減少輸入錯誤和便于修改。例如:數組大小常用宏定義

(3)預處理是在編譯之前的處理,而編譯工作的任務之一就是語法檢查,預處理不做語法檢查。

(4)宏定義末尾不加分號;

(5)宏定義寫在函數的花括號外邊,作用域為其后的程序,通常在文件的最開頭。

(6)可以用#undef命令終止宏定義的作用域

(7)宏定義可以嵌套

(8)字符串" "中永遠不包含宏

(9)宏定義不分配內存,變量定義分配內存。


2. 帶參數的宏定義:

除了一般的字符串替換,還要做參數代換

格式:   #define 宏名(參數表) 字符串

例如:#define S(a,b) a*b

(1)實參如果是表達式容易出問題

(2)宏名和參數的括號間不能有空格

(3)宏替換只作替換,不做計算,不做表達式求解

(4)函數調用在編譯后程序運行時進行,并且分配內存。宏替換在編譯前進行,不分配內存

(5)宏的啞實結合不存在類型,也沒有類型轉換。

(6)函數只有一個返回值,利用宏則可以設法得到多個值

(7)宏展開使源程序變長,函數調用不會

(8)宏展開不占運行時間,只占編譯時間,函數調用占運行時間(分配內存、保留現場、值傳遞、返回值)


iOS中常用的宏定義


上面說到宏定義主要分為參數宏和非參數宏,接下來,我們就看一下,在iOS開發過程中我們常用的一些宏定義.

  • 尺寸相關

//主屏幕的寬高
#define KmainHight  [UIScreen mainScreen].bounds.size.height

#define KmainWidth  [UIScreen mainScreen].bounds.size.width

//導航欄高度
#define KnavigationBarHeight (44)

//標簽欄高度
#define KtabBarHeight (49)


  • 顏色相關
//普通顏色
#define KmyColor(R,G,B) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:1.0]

// 隨機顏色
#define KrandomColor   [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1]

  • 語言相關
//獲取當前語言
#define KcurrentLanguage ([[NSLocale preferredLanguages] objectAtIndex:0])
  • 系統版本相關
//主要用于判斷當前iOS版本號,對其棄用或者未出現的方法進行區別對待
#define KcurrentSystemVersion [[UIDevice currentDevice] systemVersion]  

  • 手機型號相關
//iPhone5
#define IPHONE5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)

//iPhone6
#define IPHONE6 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(750, 1334), [[UIScreen mainScreen] currentMode].size) : NO)

//iPhone6 Plus
#define IPHONE6_Plus ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2208), [[UIScreen mainScreen] currentMode].size) : NO)

//Pad
#define KisPad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

  • 模擬器相關
/判斷是真機還是模擬器  
#if TARGET_OS_IPHONE  

//真機
#endif  
  
#if TARGET_IPHONE_SIMULATOR  

//模擬器

#endif  
  • 國際化相關(國際化相關知識不懂點這里)
#define LocalString(string)     NSLocalizedString(string, nil)

  • 引用相關
//弱引用
#define KweakSelf(type)  __weak typeof(type) weak##type = type;

//強引用
#define KstrongSelf(type)  __strong typeof(type) type = weak##type;
  • 沙盒相關
//獲取沙盒主路徑
#define KhomePath    NSHomeDirectory()

//獲取沙盒 Temp
#define KtempPath NSTemporaryDirectory()

//獲取沙盒 Document
#define KdocumentPath    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]

//獲取沙盒 Cache
#define KcachePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]

  • 打印相關
//對象打印
#define KobjectLog(object)  NSLog(@"%@",(object));

//整型數字打印
#define KintNumberLog(number)  NSLog(@"%d",(number));

//float數字打印
#define KfloatNumberLog(number)  NSLog(@"%f",(number));

  • 上線相關

// 自定義NSLog,在debug模式下打印,在release模式下取消一切NSLog(上線時候使用推薦:??????????)

#ifdef DEBUG

#define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);

#else

#define NSLog(FORMAT, ...) nil

#endif


內聯函數的簡介及其使用


當第一次接觸內聯函數的時候,我認為內斂函數就是宏定義,后來經過度娘的循循教導,我才知道對于內聯函數原來是另有乾坤呀.
為什么要使用內聯函數呢?其實主要是宏定義雖然簡單易懂,但是容易出錯,下面我們就舉例子說明.
比如下面的這個宏定義,其實很簡單,就是比較兩個數的大小.

#define Kmax(a, b)  (a) > (b) ? (a) : (b)

然后,我們這樣調用

int result = Kmax(i, j) + 2 ; 

其實結果就成了

 result = (i) > (j) ? (i) : (j) + 2 ; 

而我們需要的是

 result = ( (i) > (j) ? (i) : (j) ) + 2 ; 

這樣就離我們需要的期望隔著失之毫厘謬以千里....好了,這時候有人就說了,如下改動不就沒有任何問題了?但是真的沒有問題了嗎?

#define Kmax(a, b)   ((a) > (b) ? (a) : (b))

如上的修改的確可以修改上面的問題,但是我們如下使用,還是存在問題的

 result = Kmax(i++, j); 

那么預處理會處理成如下,跟我們的預想的結果還是不一致...

 result = (i++) > (j) ? (i++) : (j); 

看到上面的問題這么多,相信你們的頭和我一樣是大大的,那么這時候就我們的豬腳--->內聯函數來解決問題了,我們先看一下內聯函數的結構.

NS_INLINE (函數類型,如void,int,id) 函數名 ( 參數a,參數b,..... ) {
..........(函數實現)..........
}

就拿上面的比較方法,我們可以直接寫在PCH文件中.代碼如下.(注意:NS_INLINE是內聯函數的標志,同時要使用內聯函數,需要導入Foundation框架)這樣就完美的解決了上面的問題.

#import <Foundation/Foundation.h>

NS_INLINE int max( int a ,int b){
    
    return a>b?a:b;
    
}

下面接著是分享給大家的一個內聯函數的應用,一個自定義內聯函數彈窗.(注意:因為UIAlertView被棄用的問題,所以會爆一個黃,但是真的很好用,所以就分享一下)

#import <UIKit/UIKit.h>

#import <Foundation/Foundation.h>


NS_INLINE void tipWithMessage(NSString *message){
    
    dispatch_async(dispatch_get_main_queue(), ^{
        
        UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];
        
        [alerView show];
        
        [alerView performSelector:@selector(dismissWithClickedButtonIndex:animated:) withObject:@[@0, @1] afterDelay:0.9];
        
    });
    
}


下面對于調用也是非常的簡單,如下在-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法中,調用彈窗函數.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    tipWithMessage(@"世界,你好!");

}

下面是效果圖.


內聯函數的注意事項


內聯是以代碼膨脹(復制)為代價,僅僅省去了函數調用的開銷,從而提高函數的執行效率。如果執行函數體內代碼的時間,相比于函數調用的開銷較大,那么效率的收獲會很少。另一方面,每一處內聯函數的調用都要復制代碼,將使程序的總代碼量增大,消耗更多的內存空間。以下情況不宜使用內聯:
  • (1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。
  • (2)如果函數體內出現循環,那么執行函數體內代碼的時間要比函數調用的開銷大。


總結


關于iOS的宏定義以及內聯函數的使用就說到這里,兩者說起來各有利弊,但是不得不說的是有了宏定義以及內聯函數之后,對開發是一個不少的助力.好了,今天就說到這里了,希望文章對您有所幫助.碼字不易,跪求點贊..??
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容