从Masonry 源码探 Objective-C [源码学习开篇]

来源:互联网 发布:淘宝网皮大衣 编辑:程序博客网 时间:2024/04/29 14:15

原文链接 : http://blog.csdn.net/sinat_30162391/article/details/53321046

前言: 这个系列可能不会分析, 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 [终篇 - 有始有终 希望最后能够完美]

目录

  • Objective-C可变参数
  • 内联函数 inline
  • mas_equalTo这个宏的实现

简单介绍

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

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

  • va_list定义一个va_list变量, 这个变量的是指向参数的指针
  • va_start使用宏 定义va_list变量
  • va_argva_arg返回可变的参数,va_arg的第二个参数是你要返回的参数的类型,如果函数有多个可变参数的,依次调用va_arg获取各个参数
  • va_end用va_end宏结束可变参数的获取
- (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.width.height.mas_equalTo(@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 文件 , 剩下就是一些重命名, 和宏定义的一些东西了, 这篇就到这, 篇幅太长是没有耐心看下去的, 起个抛砖引玉的作用, 先这样, 下一篇 还不知道怎么写, 尽力写的全面一点, 让自己有所收获.

欢迎来我的交流群交流498143780
或者关注我的公共号xt1005430006 或者加我的微信 1005430006
夏天然后

2 0