iOS New TimeOC进化iOS知识总结

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

2017-02-06  本文已影响599人  被帅醒的小吴同志
调用起来

就像上面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起来去定义属于你自己项目里的高大上的吧。

上一篇下一篇

猜你喜欢

热点阅读