你帶著一個故事去聽一首歌感覺會不一樣,你帶著一個故事去找一首歌心情會不一樣。
宏定義的簡介
宏定義是C提供的三種預(yù)處理功能的其中一種,這三種預(yù)處理包括:宏定義、文件包含、條件編譯.
1. 不帶參數(shù)的宏定義:
格式: #define 標(biāo)識符 字符串
說明:
(1)宏名一般用大寫
(2)使用宏可提高程序的通用性和易讀性,減少不一致性,減少輸入錯誤和便于修改。例如:數(shù)組大小常用宏定義
(3)預(yù)處理是在編譯之前的處理,而編譯工作的任務(wù)之一就是語法檢查,預(yù)處理不做語法檢查。
(4)宏定義末尾不加分號;
(5)宏定義寫在函數(shù)的花括號外邊,作用域為其后的程序,通常在文件的最開頭。
(6)可以用#undef命令終止宏定義的作用域
(7)宏定義可以嵌套
(8)字符串" "中永遠(yuǎn)不包含宏
(9)宏定義不分配內(nèi)存,變量定義分配內(nèi)存。
2. 帶參數(shù)的宏定義:
除了一般的字符串替換,還要做參數(shù)代換
格式: #define 宏名(參數(shù)表) 字符串
例如:#define S(a,b) a*b
(1)實參如果是表達(dá)式容易出問題
(2)宏名和參數(shù)的括號間不能有空格
(3)宏替換只作替換,不做計算,不做表達(dá)式求解
(4)函數(shù)調(diào)用在編譯后程序運(yùn)行時進(jìn)行,并且分配內(nèi)存。宏替換在編譯前進(jìn)行,不分配內(nèi)存
(5)宏的啞實結(jié)合不存在類型,也沒有類型轉(zhuǎn)換。
(6)函數(shù)只有一個返回值,利用宏則可以設(shè)法得到多個值
(7)宏展開使源程序變長,函數(shù)調(diào)用不會
(8)宏展開不占運(yùn)行時間,只占編譯時間,函數(shù)調(diào)用占運(yùn)行時間(分配內(nèi)存、保留現(xiàn)場、值傳遞、返回值)
iOS中常用的宏定義
上面說到宏定義主要分為參數(shù)宏和非參數(shù)宏,接下來,我們就看一下,在iOS開發(fā)過程中我們常用的一些宏定義.
-
尺寸相關(guān)
//主屏幕的寬高
#define KmainHight [UIScreen mainScreen].bounds.size.height
#define KmainWidth [UIScreen mainScreen].bounds.size.width
//導(dǎo)航欄高度
#define KnavigationBarHeight (44)
//標(biāo)簽欄高度
#define KtabBarHeight (49)
-
顏色相關(guān)
//普通顏色
#define KmyColor(R,G,B) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:1.0]
// 隨機(jī)顏色
#define KrandomColor [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1]
-
語言相關(guān)
//獲取當(dāng)前語言
#define KcurrentLanguage ([[NSLocale preferredLanguages] objectAtIndex:0])
-
系統(tǒng)版本相關(guān)
//主要用于判斷當(dāng)前iOS版本號,對其棄用或者未出現(xiàn)的方法進(jìn)行區(qū)別對待
#define KcurrentSystemVersion [[UIDevice currentDevice] systemVersion]
-
手機(jī)型號相關(guān)
//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)
-
模擬器相關(guān)
/判斷是真機(jī)還是模擬器
#if TARGET_OS_IPHONE
//真機(jī)
#endif
#if TARGET_IPHONE_SIMULATOR
//模擬器
#endif
-
國際化相關(guān)(國際化相關(guān)知識不懂點(diǎn)這里)
#define LocalString(string) NSLocalizedString(string, nil)
-
引用相關(guān)
//弱引用
#define KweakSelf(type) __weak typeof(type) weak##type = type;
//強(qiáng)引用
#define KstrongSelf(type) __strong typeof(type) type = weak##type;
-
沙盒相關(guān)
//獲取沙盒主路徑
#define KhomePath NSHomeDirectory()
//獲取沙盒 Temp
#define KtempPath NSTemporaryDirectory()
//獲取沙盒 Document
#define KdocumentPath [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
//獲取沙盒 Cache
#define KcachePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]
-
打印相關(guān)
//對象打印
#define KobjectLog(object) NSLog(@"%@",(object));
//整型數(shù)字打印
#define KintNumberLog(number) NSLog(@"%d",(number));
//float數(shù)字打印
#define KfloatNumberLog(number) NSLog(@"%f",(number));
-
上線相關(guān)
// 自定義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
內(nèi)聯(lián)函數(shù)的簡介及其使用
當(dāng)?shù)谝淮谓佑|內(nèi)聯(lián)函數(shù)的時候,我認(rèn)為內(nèi)斂函數(shù)就是宏定義,后來經(jīng)過度娘的循循教導(dǎo),我才知道對于內(nèi)聯(lián)函數(shù)原來是另有乾坤呀.
為什么要使用內(nèi)聯(lián)函數(shù)呢?其實主要是宏定義雖然簡單易懂,但是容易出錯,下面我們就舉例子說明.
比如下面的這個宏定義,其實很簡單,就是比較兩個數(shù)的大小.
#define Kmax(a, b) (a) > (b) ? (a) : (b)
然后,我們這樣調(diào)用
int result = Kmax(i, j) + 2 ;
其實結(jié)果就成了
result = (i) > (j) ? (i) : (j) + 2 ;
而我們需要的是
result = ( (i) > (j) ? (i) : (j) ) + 2 ;
這樣就離我們需要的期望隔著失之毫厘謬以千里....好了,這時候有人就說了,如下改動不就沒有任何問題了?但是真的沒有問題了嗎?
#define Kmax(a, b) ((a) > (b) ? (a) : (b))
如上的修改的確可以修改上面的問題,但是我們?nèi)缦率褂?還是存在問題的
result = Kmax(i++, j);
那么預(yù)處理會處理成如下,跟我們的預(yù)想的結(jié)果還是不一致...
result = (i++) > (j) ? (i++) : (j);
看到上面的問題這么多,相信你們的頭和我一樣是大大的,那么這時候就我們的豬腳--->內(nèi)聯(lián)函數(shù)來解決問題了,我們先看一下內(nèi)聯(lián)函數(shù)的結(jié)構(gòu).
NS_INLINE (函數(shù)類型,如void,int,id) 函數(shù)名 ( 參數(shù)a,參數(shù)b,..... ) {
..........(函數(shù)實現(xiàn))..........
}
就拿上面的比較方法,我們可以直接寫在PCH文件中.代碼如下.(注意:NS_INLINE是內(nèi)聯(lián)函數(shù)的標(biāo)志,同時要使用內(nèi)聯(lián)函數(shù),需要導(dǎo)入Foundation框架)這樣就完美的解決了上面的問題.
#import <Foundation/Foundation.h>
NS_INLINE int max( int a ,int b){
return a>b?a:b;
}
下面接著是分享給大家的一個內(nèi)聯(lián)函數(shù)的應(yīng)用,一個自定義內(nèi)聯(lián)函數(shù)彈窗.(注意:因為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];
});
}
下面對于調(diào)用也是非常的簡單,如下在-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法中,調(diào)用彈窗函數(shù).
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
tipWithMessage(@"世界,你好!");
}
下面是效果圖.
內(nèi)聯(lián)函數(shù)的注意事項
內(nèi)聯(lián)是以代碼膨脹(復(fù)制)為代價,僅僅省去了函數(shù)調(diào)用的開銷,從而提高函數(shù)的執(zhí)行效率。如果執(zhí)行函數(shù)體內(nèi)代碼的時間,相比于函數(shù)調(diào)用的開銷較大,那么效率的收獲會很少。另一方面,每一處內(nèi)聯(lián)函數(shù)的調(diào)用都要復(fù)制代碼,將使程序的總代碼量增大,消耗更多的內(nèi)存空間。以下情況不宜使用內(nèi)聯(lián):
-
(1)如果函數(shù)體內(nèi)的代碼比較長,使用內(nèi)聯(lián)將導(dǎo)致內(nèi)存消耗代價較高。
-
(2)如果函數(shù)體內(nèi)出現(xiàn)循環(huán),那么執(zhí)行函數(shù)體內(nèi)代碼的時間要比函數(shù)調(diào)用的開銷大。