iOS源码探究相关鸡汤文Swift

厚积薄发之从Masonry 源码看Objective-C [开篇

2016-11-24  本文已影响1768人  夏天然后

前言: 这个系列可能不会分析, Masonry如何如何好, 估计多在分析源码写法, 不清楚的语法, 用了什么知识点, 可能是这样, 写成什么样也不确定, Masonry 是一个关于iOS开发的布局框架, Masonry是对NSLayoutConstraint 的封装, 你知道的NSLayoutConstraint这个家伙使用起来很麻烦的, 语法相当的啰嗦. 所以Masonry 简化了这个家伙的使用方式, 同时Masonry有一个小兄弟, 也在成长中, 成长的也是不错, 你可以在Masonry的家里找到这个家伙(SnapKit), 不同的是SnapKit 是使用Siwft 写的, 如果你都知道, 就当是我在凑字数(来 qq群打我好啦 认真脸), 今天就主要介绍一些Masonry 相关的干货, 反正你知道我是学习记录, 谈不上分享的, 我一贯就是这个态度的[囧].
下面的这张图, 简单介绍了Masonry的主要大部分类, 你说: 没写全? 对的. 我能说没有地方画让我删了吗? 认真.

可能会写这样几篇
厚积薄发之从Masonry 源码看Objective-C [开篇]
[厚积薄发之从Masonry 源码看Objective-C [开篇 续]]
[厚积薄发之从Masonry 源码看Objective-C [开篇 续续]
[厚积薄发之从Masonry 源码看Objective-C [开篇 续续续]
[厚积薄发之从Masonry 源码看Objective-C [终篇 - 有始有终 希望最后能够完美]

功力有限写什么样, 算什么样. 有点死猪不怕烫的意思. 逃跑~.

目录

简单介绍

可变参数: 在开始之前, 我决定先看看这个小知识, 当然你了解C 语言对此并不陌生, 然而我不像你, 我已经把以前学的知识, 交还给我的teacher了. 你可能也忘记了来跟我一起复习一遍, 在C 语言中的解释大致是这个样子的, 可变参数的实现必然不能缺少VA_LIST,
VA_LIST 是在C语言中是这样解释的, 用来解决变参问题的一组宏,所在头文件:#include <stdarg.h>,用于获取不确定个数的参数
而在Objective-C中 同样也有关于处理不确定参数个数的实现使用va_list相关, 接下来通过一段简单的代码进行演示.

可变参数在OC中如何实现?

- (NSMutableArray *)vaListUsing:(NSString *)p1,...NS_REQUIRES_NIL_TERMINATION{
    NSMutableArray *array = [NSMutableArray array];
    // 第一个参数进数组
    [array addObject:p1];
    // 定义一个va_list变量, 这个变量的是指向参数的指针
    va_list v;
    id vStr;
    // 使用宏定义va_list变量
    va_start(v, p1);
    // va_arg返回可变的参数,va_arg的第二个参数是你要返回的参数的类型,如果函数有多个可变参数的,依次调用va_arg获取各个参数
    while ((vStr = va_arg(v, id))) {
        [array addObject:vStr];
    }
    // 用va_end宏结束可变参数的获取
    va_end(v);
    return array;
}
NSMutableArray *array = [self vaListUsing:@"Cancel", @"Other",@"OK", nil];
NSLog(@"%@", array); 

这是获取的打印结果, 以上就是我通过代码的形式表现出来的, 你可以通过获取的参数名, 参数个数, 可进行适当的UI布局什么的.
2016-11-23 15:58:09.225 Masonry阅读理解****[5338:1112595] (*
** Cancel,**
** Other,**
** OK**
)

以上是不是跑题了, 我的回答是 并没有! 你也相信我不能在这瞎扯淡.
接下来看看Masonry中如何使用这个小知识的呢.

在MASUtilities中

先看下面这段源码, 通过上面的介绍, 我觉的你可能有点能明白了, 稍后解释代码, 首先看看inline C和C++语言中inline用来声明内联函数的, 我还是有些印象的 作用是是 用来替代C中表达式形式的宏定义的. 而在OC用也是有同样的作用.

static inline id _MASBoxValue(const char *type, ...) {
    va_list v;
    va_start(v, type);
    id obj = nil;
    if (strcmp(type, @encode(id)) == 0) {
        id actual = va_arg(v, id);
        obj = actual;
    } else if (strcmp(type, @encode(CGPoint)) == 0) {
        CGPoint actual = (CGPoint)va_arg(v, CGPoint);
        obj = [NSValue value:&actual withObjCType:type];
    } else if (strcmp(type, @encode(CGSize)) == 0) {
        CGSize actual = (CGSize)va_arg(v, CGSize);
        obj = [NSValue value:&actual withObjCType:type];
    } else if (strcmp(type, @encode(MASEdgeInsets)) == 0) {
        MASEdgeInsets actual = (MASEdgeInsets)va_arg(v, MASEdgeInsets);
        obj = [NSValue value:&actual withObjCType:type];
    } else if (strcmp(type, @encode(double)) == 0) {
        double actual = (double)va_arg(v, double);
        obj = [NSNumber numberWithDouble:actual];
    } else if (strcmp(type, @encode(float)) == 0) {
        float actual = (float)va_arg(v, double);
        obj = [NSNumber numberWithFloat:actual];
    } else if (strcmp(type, @encode(int)) == 0) {
        int actual = (int)va_arg(v, int);
        obj = [NSNumber numberWithInt:actual];
    } else if (strcmp(type, @encode(long)) == 0) {
        long actual = (long)va_arg(v, long);
        obj = [NSNumber numberWithLong:actual];
    } else if (strcmp(type, @encode(long long)) == 0) {
        long long actual = (long long)va_arg(v, long long);
        obj = [NSNumber numberWithLongLong:actual];
    } else if (strcmp(type, @encode(short)) == 0) {
        short actual = (short)va_arg(v, int);
        obj = [NSNumber numberWithShort:actual];
    } else if (strcmp(type, @encode(char)) == 0) {
        char actual = (char)va_arg(v, int);
        obj = [NSNumber numberWithChar:actual];
    } else if (strcmp(type, @encode(bool)) == 0) {
        bool actual = (bool)va_arg(v, int);
        obj = [NSNumber numberWithBool:actual];
    } else if (strcmp(type, @encode(unsigned char)) == 0) {
        unsigned char actual = (unsigned char)va_arg(v, unsigned int);
        obj = [NSNumber numberWithUnsignedChar:actual];
    } else if (strcmp(type, @encode(unsigned int)) == 0) {
        unsigned int actual = (unsigned int)va_arg(v, unsigned int);
        obj = [NSNumber numberWithUnsignedInt:actual];
    } else if (strcmp(type, @encode(unsigned long)) == 0) {
        unsigned long actual = (unsigned long)va_arg(v, unsigned long);
        obj = [NSNumber numberWithUnsignedLong:actual];
    } else if (strcmp(type, @encode(unsigned long long)) == 0) {
        unsigned long long actual = (unsigned long long)va_arg(v, unsigned long long);
        obj = [NSNumber numberWithUnsignedLongLong:actual];
    } else if (strcmp(type, @encode(unsigned short)) == 0) {
        unsigned short actual = (unsigned short)va_arg(v, unsigned int);
        obj = [NSNumber numberWithUnsignedShort:actual];
    }
    va_end(v);
    return obj;
}

#define MASBoxValue(value) _MASBoxValue(@encode(__typeof__((value))), (value))

由源代码引申之内联函数

定义: 内联函数是指用inline关键字修饰的函数
作用: 去掉函数调用带来的开销
这个说的可以 可以去看看
代码示例
仿照Masonry的示例代码, 我简单测试了一下, 准确性有待考察, 不过粗略的看, 貌似内联函数效率高一点, 你怎么看? 欢迎评论拍砖. 教我做人.

static inline

static inline int xtAdd(int x, int y){
    int res = x + y;
    return res;
}
#define RESXyAdd(x, y) xtAdd(x, y)
    NSDate *tmpStartData = [NSDate date];
    int res = RESXyAdd(2, 3);
    // 内联
    // 2016-11-24 14:06:13.816 Masonry解析[7209:1504811] >>>>>>>>>>cost time = 0.608981 ms
    // 2016-11-24 14:00:57.229 Masonry解析[6870:1496409] >>>>>>>>>>cost time = 0.648022 ms
    // 2016-11-24 14:01:38.670 Masonry解析[6898:1497238] >>>>>>>>>>cost time = 0.645995 ms
    // 非内联
    // 2016-11-24 14:03:57.975 Masonry解析[7052:1500940] >>>>>>>>>>cost time = 0.657976 ms
    // 2016-11-24 14:04:57.955 Masonry解析[7101:1502351] >>>>>>>>>>cost time = 0.651002 ms
    NSLog(@"res === %d", res);
    double deltaTime = [[NSDate date] timeIntervalSinceDate:tmpStartData];
    NSLog(@">>>>>>>>>>cost time = %f ms", deltaTime * 1000);

接下来通过Masonry的使用来解释上面提到的代码
首先我定义了一个View 距上左88 宽高88 我分别可以使用make.width.height.mas_equalTo(88) make.width.height.mas_equalTo(@88) 或者 make.size.mas_equalTo(CGSizeMake(88, 88)) 通过这个宏我分别可以实现相应很多操作. 其实这些都是通过上面提到的内联函数实现的. 先通过strcmp这个库函数比较传进来的类型跟什么类型匹配, 之后放回相应的对象. 完成对象的校验. 这样的效率很高, 同时使用方便.

    UIView *view = [UIView new];
    [self.view addSubview:view];
    view.backgroundColor = [UIColor redColor];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        //
        make.top.equalTo(self.view.mas_top).with.offset(88);
        make.left.equalTo(self.view.mas_left).with.offset(88);
        // 我通过这个宏 传递88给width 和 height
        make.width.height.mas_equalTo(88);
        // 或者 @88 
        // make.width.height.mas_equalTo(@88);
        // 最终都是通过上述的内联函数实现了相应的类型对应
        // make.size.mas_equalTo(CGSizeMake(88, 88));
    }];

#define mas_equalTo(...) equalTo(MASBoxValue((VA_ARGS)))
mas_equalTo是个上面这样表示的宏定义
#define MASBoxValue(value) _MASBoxValue(@encode(typeof((value))), (value))

而 MASBoxValue 最终是上面这个宏定义, 而最终 _MASBoxValue就是最上面提到的一大坨代码(那个内联函数). 而不确定参数, 我通过文章的开头, 也进行了交代.

总结: 这个MASUtilities 文件 , 剩下就是一些重命名, 和宏定义的一些东西了, 这篇就到这, 篇幅太长是没有耐心看下去的, 起个抛砖引玉的作用, 先这样, 下一篇 还不知道怎么写, 尽力写的全面一点, 让自己有所收获.

如果有一丝丝帮助 点个关注喜欢 又何妨??
文/ 夏天然后

本文已在版权印备案,如需转载请访问版权印。36586216
获得授权

上一篇下一篇

猜你喜欢

热点阅读