iOS-宏

作者: xxxxxxxx_123 | 来源:发表于2020-04-11 17:41 被阅读0次

在日常的开发中,我们或多或少的会使用一些宏定义来提高我们变成的效率。那么什么是宏定义呢?通俗一点,宏定义就是对某些代码进行替换,在预编译的时候将定义的值又会换回去。

宏定义的分类

宏定义可以分为两类,一类称为对象宏,一类称为函数宏。

对象宏就是比较简单的常量定义。

#define K_SHORT_ANIMATION_TIME 0.3f

函数宏则是比较复杂,具有函数计算的定义,作用也是一个函数。

#define debug_NSLog(format, ...) NSLog((@"<文件名: %@-行数:(%d)> 方法名: %s: " format), [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__);

iOS常见的宏定义

  • __FILE__:当前源文件名。

  • __LINE__:当前行数。

  • __DATE__:当前的编译日期。

  • __TIME__:当前编译时间。

  • __func__C99的标准,在GCC编译器只输出函数名称

  • __FUNCTION__的作用同__func__

  • __PRETTY_FUNCTION__是一个非标准宏,会以<return-type> <class-name>::<member-function-name>(<parameters-list>)输出,即会输出返回类型、类名、函数名、参数列表。

  • __VA_ARGS__:可变参数宏,能够使用可以变化的参数列表。比如上述打印的封装,...表示可变参数,它把可变参数传给宏中的__VA_ARGS__

  • ##:链接参数。

RAC中的宏定义

RAC这个库中,有很多非常有特点的宏,其中实现的想法很值得我们借鉴。如weakify(self)定义了弱类型的self

首先,我们看到的宏如下:

#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

rac_keywordify的定义如下,可以暂时不用管。

#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif

metamacro_foreach_cxt的定义如下:

// MACRO = rac_weakify_
// SEP = 空
// CONTEXT = __weak
// ... = self
// __VA_ARGS__ = self
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

#define metamacro_concat(A, B) \
        metamacro_concat_(A, B)

#define metamacro_concat_(A, B) A ## B

metamacro_concat的意思是我们要将后面的参数拼接起来,那么我们先来看看metamacro_argcount做了什么:

// ... = self
// metamacro_at(20, self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define metamacro_argcount(...) \
        metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

// N = 20
#define metamacro_at(N, ...) \
        metamacro_concat(metamacro_at, N)(__VA_ARGS__)
// metamacro_concat(metamacro_at, 20)(self, 20, 19, ...)
// metamacro_at20(self, 20, 19, ...)

#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)
// metamacro_head(1)

#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)
        
#define metamacro_head_(FIRST, ...) FIRST

最终metamacro_argcount(__VA_ARGS__)返回的是可变参数__VA_ARGS__的参数个数,在本例中也就是1。此时metamacro_foreach_cxt就变成了:

metamacro_concat(metamacro_foreach_cxt, 1)(MACRO, SEP, CONTEXT, __VA_ARGS__)

整理一下:

metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, __VA_ARGS__)

#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

结合当前的例子就变成了:

rac_weakify_(0, __weak, self);

#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

最终就变成了:

__weak __typeof__(self) self_weak_ = self

所以,weakify(self)的最终实现就是__weak __typeof__(self) self_weak_ = self

RAC中还有很多类型的宏定义,比如说strongify(...)RACObserve等。

使用宏定义的优缺点

优点:

  • 提高了程序的可读性,比如说我们在代码中大量使用一个常数,使用宏定义清晰的给其命名,别人再来阅读代码的时候,就会简单明了些。比如:
#define SCREEN_WIDTH UIScreen.mainScreen.bounds.size.width
#define MAX_SIZE 100
  • 方便进行修改,用户只需要在一处定义,多处使用,统一修改。比如我们定义一种颜色作为我们页面的主题色,后期需要整体改动色值,那么我们只需要修改宏定义即可。
#define K_THEME_COLOR [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:(a)]
  • 提高程序的运行效率。使用带参的宏定义既可完成函数调用的功能,又能避免函数的出栈与入栈操作,减少系统开销,提高运行效率,如果有一个函数会在项目中频繁使用,可以考虑一下宏定义。
#define SXRGB16Color(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

缺点

  • 过于复杂的宏导致代码不易读。
  • 对带参的宏而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患,预编译语句仅仅是简单的值代替,缺乏类型的检测机制。
  • 未考虑充分的宏定义可能存在BUG

比如,我们定义了一个比较大小的宏,按照下面的例子执行下来却是有很多错误。

#define TMIN(A,B) A < B ? A : B
- (void)defineTest {
    int a = 2 * TMIN(2, 3);
    NSLog(@"==a==%d==", a);
    
    int b = TMIN(3, 4 < 5 ? 4 : 5);
    NSLog(@"==b==%d==", b);

    float c = 1.0;
    float d = TMIN(c++, 1.5);
    NSLog(@"==d==%f==", d);
}
宏错误.png

官方给出的比较大小的宏如下:

#if !defined(MIN)
    #define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })
    #define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)
#endif

总结

使用宏定义可以给我们的开发带来方便,但是大量的使用宏,则会带来效率上的影响。另外定义宏的时候,一定要考虑其正确性、健壮性、易读性。

相关文章

  • iOS-宏

    作用:简单说:使代码简洁,增加可读性,减少工作量。 分类:对象宏、函数宏。 比如:对象宏 这种 #define X...

  • iOS-宏

    在日常的开发中,我们或多或少的会使用一些宏定义来提高我们变成的效率。那么什么是宏定义呢?通俗一点,宏定义就是对某些...

  • iOS-宏定义

    参照C语言的预处理命令简介 : 最简单的宏 : 判断当前工程是否是ARC还是MRC 旧工程配置arc方案: 直接在...

  • iOS开发--.PCH文件创建

    .pch文件 创建.pch文件方便定义全局的宏和头文件导入 1.Command+N,打开新建文件窗口:iOS->O...

  • iOS-常用宏定义

    [转自:iOS常用宏定义][http://www.cocoachina.com/ios/20161207/1831...

  • iOS-常用宏定义

    自己常用宏定义 /*打印信息*/#ifdef DEBUG#define BRYLog( s, ... ) prin...

  • iOS-私有API与runtime

    iOS-私有API与runtime iOS-私有API与runtime

  • iOS-代码混淆加固策略

    iOS-代码混淆加固策略 iOS-代码混淆加固策略

  • iOS-性能优化深入探究

    iOS-性能优化深入探究 iOS-性能优化深入探究

  • iOS-自动打包及分发(三)

    iOS-自动打包及分发(一)iOS-自动打包及分发(二)iOS-自动打包及分发(三) 废话不多说了,上正文: 一、...

网友评论

    本文标题:iOS-宏

    本文链接:https://www.haomeiwen.com/subject/gduumhtx.html