巨集簡介: 巨集是一種批量處理的稱謂。一般說來,巨集是一種規則或模式,或稱語法替換 ,用於說明某一特定輸入(通常是字元串)如何根據預定義的規則轉換成對應的輸出(通常也是字元串)。這種替換在預編譯時進行,稱作巨集展開。編譯器會在編譯前掃描代碼,如果遇到我們已經定義好的巨集那麼就會進行代碼替換,巨集只會在記憶體中co ...
巨集簡介:
巨集是一種批量處理的稱謂。一般說來,巨集是一種規則或模式,或稱語法替換 ,用於說明某一特定輸入(通常是字元串)如何根據預定義的規則轉換成對應的輸出(通常也是字元串)。這種替換在預編譯時進行,稱作巨集展開。編譯器會在編譯前掃描代碼,如果遇到我們已經定義好的巨集那麼就會進行代碼替換,巨集只會在記憶體中copy一份,然後全局替換,巨集一般分為對象巨集和函數巨集(下麵會詳細介紹)。
巨集的弊端:
如果代碼中大量的使用巨集會是的編譯時間變長。
對象巨集:
像這樣:#define M_PI 3.14159265358979323846264338327950288
這個沒什麼好講的,我想只要是個iOS程式員就都會用。
下麵附送一波我們在工程中常用的巨集
//獲取屏幕的寬和高 #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define SCREENH_HEIGHT [UIScreen mainScreen].bounds.size.height //設置隨機顏色 #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 LRRGBColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] #define LRRGBAColor(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(r)/255.0 blue:(r)/255.0 alpha:a] // clear背景顏色 #define LRClearColor [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"]) // 判斷是否為 iPhone 5SE #define iPhone5SE [[UIScreen mainScreen] bounds].size.width == 320.0f && [[UIScreen mainScreen] bounds].size.height == 568.0f // 判斷是否為iPhone 6/6s #define iPhone6_6s [[UIScreen mainScreen] bounds].size.width == 375.0f && [[UIScreen mainScreen] bounds].size.height == 667.0f // 判斷是否為iPhone 6Plus/6sPlus #define iPhone6Plus_6sPlus [[UIScreen mainScreen] bounds].size.width == 414.0f && [[UIScreen mainScreen] bounds].size.height == 736.0f //獲取系統版本 #define IOS_SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] floatValue] //判斷 iOS 8 或更高的系統版本 #define IOS_VERSION_8_OR_LATER (([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0)? (YES):(NO)) //判斷是真機還是模擬器 #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。