宏簡介:
宏是一種批量處理的稱謂。一般說來,宏是一種規則或模式,或稱語法替換 ,用于說明某一特定輸入(通常是字符串)如何根據預定義的規則轉換成對應的輸出(通常也是字符串)。這種替換在預編譯時進行,稱作宏展開。編譯器會在編譯前掃描代碼,如果遇到我們已經定義好的宏那么就會進行代碼替換,宏只會在內存中copy一份,然后全局替換,宏一般分為對象宏和函數宏(下面會詳細介紹)。
宏的弊端:
如果代碼中大量的使用宏會是的編譯時間變長。
對象宏:
像這樣:#define M_PI 3.141592653
項目中常用的對象宏
//獲取iOS版本號
#define kIOSVersions [[[UIDevice currentDevice] systemVersion] floatValue]
//獲取window
#define kUIWindow [[[UIApplication sharedApplication] delegate] window] //獲得window
//獲取屏幕的寬和高
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height
//獲取狀態欄高度
#define Height_StatusBar [[UIApplication sharedApplication] statusBarFrame].size.height
//導航欄加狀態欄高度
#define Height_NavBar (Height_StatusBar >20?88.0f: 64.0f)
//獲取安全區高度
#define Height_SafeArea (Height_StatusBar >20?34.0f: 0.00f)
//tabbar高度+SafeArea高度
#define Height_Tabbar (Height_StatusBar >20? 83:49)
//設置隨機顏色
#define LRRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]
//設置RGB和RGB顏色
#define RGBColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
//16進制顏色
#define ColorWithHexValue(hexValue) [UIColor colorWithRed:((float)((hexValue & 0xFF0000) >> 16))/255.0 green:((float)((hexValue & 0xFF00) >> 8))/255.0 blue:((float)(hexValue & 0xFF))/255.0 alpha:1.0]
#define RGBAColor(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(r)/255.0 blue:(r)/255.0 alpha:a]
// clear背景顏色
#define ClearColor [UIColor clearColor]
//判斷是否為iPhone
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
//判斷是否為iPad
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
//判斷是否為ipod
#define IS_IPOD ([[[UIDevice currentDevice] model] isEqualToString:@"iPod touch"])
//獲取系統版本
#define IOS_SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] floatValue]
//判斷 iOS 8 或更高的系統版本
#define IOS_VERSION_8_OR_LATER (([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0)? (YES):(NO))
// 快速宏定義__weak
#define KWeakObj(weakName,objName) __weak typeof(&*objName) weakName = objName
// 快速宏定義__block
#define KBlockObj(blockName,objName) __block typeof(&*objName) blockName = objName
//判斷是真機還是模擬器
#if TARGET_OS_IPHONE
//iPhone Device
#endif
#if TARGET_IPHONE_SIMULATOR
//iPhone Simulator
#endif
//沙盒目錄文件
//獲取temp
#define kPathTemp NSTemporaryDirectory()
//獲取沙盒 Document
#define kPathDocument [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
//獲取沙盒 Cache
#define kPathCache [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]
//NSLog
#define NSLog(format, ...) do { \
fprintf(stderr, "<%s : %d> %s\n", \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \
__LINE__, __func__); \
(NSLog)((format), ##__VA_ARGS__); \
fprintf(stderr, "-------\n"); \
} while (0)
函數宏:
其實說到宏那么不得不提的就是在宏中常用的預處理命令和運算符
指令及作用:
#空指令,無任何效果
#define定義宏
#undef取消已定義的宏
#if如果給定條件為真,則編譯下面代碼
#ifdef如果宏已經定義,則編譯下面代碼
#ifndef如果宏沒有定義,則編譯下面代碼
#elif如果前面的#if給定條件不為真,當前條件為真,則編譯下面代碼
#endif結束一個#if……#else條件編譯塊
#error停止編譯并顯示錯誤信息
#運算符:
例如: #define demo1(n) "123"#n
出現在宏定義中的#運算符把跟在其后的參數轉換成一個字符串。有時把這種用法的#稱為字符串化運算符
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%s",demo1(abc));
}
//打印會輸出 123abc
##運算符:
例如:#define demo2(m,n,j) m##n##j
##運算符用于把參數連接到一起。預處理程序把出現在##兩側的參數合并成一個符號
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%d",demo2(1, 2, 3));
}
//打印會輸出 123
舉例:
//宏定義
#ifndef weakify
#define weakify(o) __weak typeof(o) weak##o = o;
#define strongify(o) __strong typeof(o) o = weak##o;
#endif
//調用
-(void)demo2
{
weakify(_v2)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSInteger count =0;
strongify(_v2)
while( count<10) {
count++;
NSLog(@"---------%@---%ld",weak_v2,(long)count);
sleep(1);
}
});
//3秒后將 self.v2對象 銷毀
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
self.v2=nil;
});
}
上面定義了兩個宏,第一個相當于實現了__weak typeof(self) weakself = self;
用##把weak和self連接起來,實現了self對block的弱引用,第二個宏的作用是保護block里的__weakself防止self被釋放后block里的 __weakself也被釋放(如果block在棧區,會將block copy一份到堆區,如果block在堆區,就在copy一份在堆區,此時block的引用計數為2)。
在上面demo2中_v2是當前類的屬性,在并發隊列線程的block中用strongify保護起來,在3秒后self.v2釋放,但由于self.v2被copy一份到堆區,所以依然可以打印_v2。