宏简介:
宏是一种批量处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。编译器会在编译前扫描代码,如果遇到我们已经定义好的宏那么就会进行代码替换,宏只会在内存中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。