iOS:学会使用宏,让工程更加高大上

我就是高大上
我就是高大上

写在前面

好像有一段时间没有更新简书了,年前项目期很忙,又赶上了公司被盗,电脑在公司丢了,算了想想都是泪,过年时候也忘了更,好吧,以后算是给自己一个任务,尽量一周更一篇,废话不多说直奔主题。

宏的使用

有时候我们在研究一些开源三方库的源码时会发现,const常量文件或者.h pch文件里会加入一些自己定义的宏,当然这也是必不可少的,一个库也好,项目也好,因为有让调用起来更简单,更高大上。

在宏中进行条件判断一般用#if 结束时#endif
例如我们最常见的控制台调试

#ifdef DEBUG
#define NSLog(format, ...) printf("\n[%s] %s [第%d行] %s\n", __TIME__, __FUNCTION__, __LINE__, [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String]);
#else
#define NSLog(format, ...)
#endif

好的,你也许会发现MJconst文件里是长这个样子的:

// 过期
#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)

// 构建错误
#define MJExtensionBuildError(clazz, msg) \
NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
[clazz setMj_error:error];

// 日志输出
#ifdef DEBUG
#define MJExtensionLog(...) NSLog(__VA_ARGS__)
#else
#define MJExtensionLog(...)
#endif

/**
 * 断言
 * @param condition   条件
 * @param returnValue 返回值
 */
#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
[clazz setMj_error:nil]; \
if ((condition) == NO) { \
    MJExtensionBuildError(clazz, msg); \
    return returnValue;\
}

调用起来是这个样子的:

调用起来

就像上面MJExtensionDeprecated实际上是一个用来提示已废弃

我们来剖析一下上面定义宏的形式,很基础,希望帮助那些还在进步的coder们大神现在可以撤退啦

#define MJExtensionDeprecated(instead)  NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)

我们发现除了可以定义一些静态的常量外,也是可以传参的,在上面instead就被作为参数传到了后面,NS_DEPRECATED是系统宏 :

系统宏

NS_DEPRECATEDNS_AVAILABLE这两个宏很常见,NS_DEPRECATED表示在什么版本以后被废除,其中四个参数分别表示mac os的版本以后废除的描述iOS版本以后废除的描述NS_AVAILABLE宏则表示什么版本以后可用。
想必看到这就已经知道不再畏惧成堆的系统宏了,奥,原来MJExtensionDeprecated只是为了方便调用又重新定义了一遍,原来完全可以用:

说到这里既然也可以传参去使用,那么我们是不是一下子想到了很多?
譬如:

//对于frame的定义
#define Frame(x, y, width, height) CGRectMake((x),(y),(width),(height))

//对于size的定义
#define Size(width, height) CGSizeMake((width), (height))

//针对于iphone6尺寸的实际高度和宽度
#define HeightScale_IOS6(height) ((height/667.0) * Screen_height)
#define WidthScale_IOS6(width) ((width/375.0) * Screen_width)

//对于字体的定义:
#define font(size) [UIFont systemFontOfSize:(size)]

等等,只要你觉得方便的都可以去定义,甚至于我们还可以利用的特性去将一大串代码缩减至一句话(敲黑板了):
譬如MJ的状态检查,当需要在很多方法内调用相同的代码时大可以去宏定义一个:

// 状态检查
#define MJRefreshCheckState \
MJRefreshState oldState = self.state; \
if (state == oldState) return; \
[super setState:state];
调用demo

调用起来就一句话,如果这里有萌新,提示一下'\' 是换行符 不加入宏定义逻辑内。

我们甚至可以去定义一些烦恼的长代码段,例如定义一个单例(这里的##双井号是连接符,意思是将class类名与shared进行拼接,比如当classCat时,wyh_singleton_interface(Cat)定义的就是+(instancetype)sharedCat):

//.h
#define wyh_singleton_interface(class) + (instancetype)shared##class;

//.m
#define wyh_singleton_implementation(class) \
static class *_instance; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
\
return _instance; \
} \
\
+ (instancetype)shared##class \
{ \
if (_instance == nil) { \
_instance = [[class alloc] init]; \
} \
\
return _instance; \
}

在类的.h中就一行代码搞定~:


#import <Foundation/Foundation.h>

@interface Person : NSObject

wyh_singleton_interface(Person)


@end

#import "Person.h"

@implementation Person

wyh_singleton_implementation(Person)


@end

这样写完后,你便可以这样去创建一个Person的单例类:


- (void)viewDidLoad {
    [super viewDidLoad];

    Person *per = [Person sharedPerson];
}

是不是很简单,很神奇,很高大上,,我们再举几个例子:

NSAssert一般大神们都习惯去用的debug模式断言宏,这个宏是系统宏与NSCAssert差不多只不过一个OC用一个C用,想进一步了解一下这个宏的放传送门

戳死我呀~

示例

经过上面的介绍想必我们已经可以看懂上面的系统宏定义,NSAssert(condition, desc, ...)需要传入两个参数conditiondesc,其中condition是条件判断,desc是如果不成立的描述。

我们分析一下,当!(condition)也就是condition == NO的时候(即不成立的时候),NSAssertionHandler这个类的实例一般由系统自动创建,用于评估处理错误断言,如果NSAssert条件评估为NO,会向这个NSAssertionHandler实例发送一个错误描述desc,并且执行handleFailureInMethod:方法。

简单的来讲,就是当condition == NO时,程序会抛出异常,并在控制台打印错误信息。
好了到这就明白了,为什么大神都喜欢用NSAssert去断言,下面放个例子:

- (void)viewDidLoad {

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    NSString *str = @"我是梁朝伟";
    
    NSAssert([str isEqualToString:@"我是刘德华"], @"当str是刘德华时才能享受待遇");

}

这时运行程序,我们会发现程序崩溃:

示例2

好了 现在是不是很清楚宏的作用了,那是不是我们项目中把所有常量都交给宏,定义一大堆宏就逼格够高啦?

当然不是,因为如果一个项目过多的使用宏定义会增加程序预编译的时间,(因为宏是每次初始化都执行一次)这对debug调试来说无疑是不想看到的,所以一些静态常量就交给const修饰的常量吧(const常量初始化后只执行一次) ,这样就节约了程序运行的时间,普及一下const常量定义方法。

//.h中声明定义
UIKIT_EXTERN NSString * const HWPayReqCode;       

UIKIT_EXTERN NSString * const HWHttpRequestCache; 

UIKIT_EXTERN NSString * const HWLogoIconUrl;

//.m中实现定义

NSString * const HWPayReqCode = @"HWPayReqCode"; 

NSString * const HWHttpRequestCache = @"HWHttpRequestCache";

NSString * const HWLogoIconUrl = @"https://baidu.com";

最后,合理利用宏和静态常量使得项目中的全局调用变得更方便更有序,这篇文章就是抽空写一点无任何难度但容易被人忽略的问题,希望大家赶紧get起来去定义属于你自己项目里的高大上的吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • iOS宏的经典用法Apple的习惯attribute iOS宏的经典用法1.常量宏、表达式宏 define kTa...
    reallychao阅读 3,853评论 0 0
  • 1.NSAssert NSAssert()是一个宏,用于开发阶段调试程序中的Bug,通过为NSAssert()传递...
    字节码阅读 1,533评论 0 5
  • A fast, convenient and nonintrusive conversion between JS...
    纸简书生阅读 6,339评论 8 32
  • 在其位某其事,她觉得自己没有多大的本事,占着茅坑不拉屎确实不好,所以才辞职出去闯荡! 只是外面的世界不如她想的这么...
    莲芯子阅读 199评论 0 0
  • 八 心存欢喜,到哪里都不孤寂。因为欢喜着这个人间,走的越陌生就越浪漫。即便枯燥乏味,也找出新鲜的白天黑夜来...
    龙青阅读 371评论 0 4