学海无涯

iOS-宏

2020-04-11  本文已影响0人  xxxxxxxx_123

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

宏定义的分类

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

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

#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常见的宏定义

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]

缺点

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

#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

总结

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

上一篇 下一篇

猜你喜欢

热点阅读