平常我们开发中不可避免用到一些宏,特此记录下。
一、自己常常写的宏
尺寸宏
// 宽和高基本都是用的
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
// navigationBar 默认的高度
#define NAVIGATIONBAR_HEIGHT 64
// tabBar 默认的高度
#define UITABBAR_HEIGHT 49
颜色宏
// RGB颜色转换(16进制->10进制)
#define UICOLOR_HEX(hexString) [UIColor colorWithRed:((float)((hexString & 0xFF0000) >> 16))/255.0 green:((float)((hexString & 0xFF00) >> 8))/255.0 blue:((float)(hexString & 0xFF))/255.0 alpha:1.0]
// 带有RGBA的颜色设置
#define UICOLOR_RGB(R, G, B, A) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:A]
// 随机颜色
#define UICOLOR_RANDOM [UIColor colorWithRed:(arc4random()%255)/255.0 green:(arc4random()%255)/255.0 blue:(arc4random()%255)/255.0 alpha:1.0]
打印宏
// 直接替换
#ifdef DEBUG
#define NSLog(...) NSLog(__VA_ARGS__)
#define debugMethod() NSLog(@"%s", __func__)
#else
#define NSLog(...)
#define debugMethod()
#endif
真机还是模拟器
#if TARGET_OS_IPHONE
//iPhone Device
#endif
#if TARGET_IPHONE_SIMULATOR
//iPhone Simulator
#endif
\ 行继续操作符
#define DEFINE_SINGLETON_FOR_CLASS(className) \
\
+ (className *)sharedManager { \
static className *shared##className = nil; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
@synchronized(self){ \
shared##className = [[self alloc] init]; \
} \
}); \
return shared##className; \
}
系统宏
//获取系统版本
#define IOS_VERSION [[[UIDevice currentDevice] systemVersion] floatValue]
// 大于 iOS 8 的系统
#define ABOVE_IOS8 (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) ? YES : NO)
// 直接判断机型
#define IS_IPHONE_4 (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)480) < DBL_EPSILON)
#define IS_IPHONE_5 (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)568) < DBL_EPSILON)
#define IS_IPHONE_6 (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)667) < DBL_EPSILON)
#define IS_IPHONE_6_PLUS (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)736) < DBL_EPSILON)
目录宏
// Directory 目录
#define PATH_DIRECTORY [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
// Cache 目录
#define PATH_CACHE [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
// 数据库 目录
#define PATH_DATABASE_CACHE [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]
weakify & strongify
#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif
#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif
区分不同版本的文字宽度处理
PS: MBProgressHUD 获取
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \
sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero;
#else
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero;
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \
boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \
attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero;
#else
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \
sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero;
#endif
某些场景的宏
例如 KVO 中的那个 KeyPath, 有时我们直接输入,并不好输入,而且容易输入错误,没有提示。
这样写后,直接有提示,而且方便。
#define PQ_KEY_PATH(objc,keyPath) @(((void)objc.keyPath,#keyPath))
PQ_KEY_PATH(self.tableView, contentOffset);
同时,我们要注意在 Swift 中已经没有宏啦,为什么会没有呢?不可否认的是宏定义很可能隐藏很多 bug,这对于开发其实并不是一件好事。所以我们在使用的时候必须注意,具体可以看看喵神的宏定义的黑魔法 - 宏菜鸟起飞手册。
二、自带的宏
// 获取两者之间小的
#define MIN(A,B) ((A) < (B) ? (A) : (B))
// 获取两者之间大的
#define MAX(A,B) ((A) > (B) ? (A) : (B))
// 绝对值
#define ABS(A) ((A) < 0 ? (-(A)) : (A))
//CGFLOAT_MAX 无穷大
//CGFLOAT_MIN 无穷接近0
#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif
// 这三个倒是用的不多
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
// UIKIT_EXTERN extern
#ifdef __cplusplus
#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define UIKIT_EXTERN extern __attribute__((visibility ("default")))
#endif
NS_CLASS_AVAILABLE_IOS(7_0)
NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.");
相对来说,这块自身提供其实可以是常用的。特别是MIN
,MAX
,CGFLOAT_MIN
都是常常用到的。
三、用于判断或注释的
#define 定义一个预处理宏
#undef 取消宏的定义
#if 编译预处理中的条件命令, 相当于C语法中的if语句
#ifdef 判断某个宏是否被定义(#define过), 若已定义, 执行随后的语句
#ifndef 与#ifdef相反, 判断某个宏是否未被定义
#elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足, 则执行#elif之后的语句, 相当于C语法中的else-if
#else 与#if, #ifdef, #ifndef对应, 若这些条件不满足, 则执行#else之后的语句, 相当于C语法中的else
#endif #if, #ifdef, #ifndef这些条件命令的结束标志.
defined 与#if, #elif配合使用, 判断某个宏是否被定义
#ifdef PQ_MAX
// 如果定义了宏PQ_MAX,则编译此处的代码
#else
// 如果没有定义宏PQ_MAX,则编译此处的代码
#endif
#ifndef PQ_MAX
// 如果没有定义宏PQ_MAX,则编译此处的代码
#elif PQ_MAX_INT
// 如果定义了宏PQ_MAX,同时还定义了宏PQ_MAX_INT,则编译此处的代码
#else
// 定义了宏PQ_MAX,但是没有定义宏PQ_MAX_INT,则编译此处的代码
#endif
#pragma 说明编译器信息
#warning 显示编译警告信息
#error 显示编译错误信息