在swift中使用内联复合表达式

OC是C的超集

在OC中,我们可以使用一种名为内联复合表达式的语法 http://blog.sunnyxx.com/2014/08/02/objc-weird-code/

利用这个特性,我们可以在iOS开发中写复杂的页面布局时,做到类似HTML的标签化的语法.使布局结构和视图层级清晰明了.

举个例子:

有如下布局需求

布局示意图

HTML代码:

<div class="out">
    <div class="middle">
        <div class="inner">
            <p>content1</p>
        </div>
    </div>
    <div class="middle">
        <div class="inner">
            <p>content2</p>
        </div>
        <div class="inner">
            <p>content3</p>
        </div>
    </div>
</div>

可以看出,HTML代码的视图层级关系非常清晰.

使用OC代码布局,但不使用复合内联表达式的写法如下:

    UIView *outContainer = [UIView new];
    [self.view addSubview:outContainer];
    [outContainer mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];
    
    UIView *midContainer1 = [UIView new];
    [outContainer addSubview:midContainer1];
    [midContainer1 mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];
    
    UILabel *textLabel1 = [UILabel new];
    [midContainer1 addSubview:textLabel1];
    [textLabel1 mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];
    
    UIView *midContainer2 = [UIView new];
    [outContainer addSubview:midContainer2];
    [midContainer2 mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];

    UILabel *textLabel2 = [UILabel new];
    [midContainer2 addSubview:textLabel2];
    [textLabel2 mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];

    UILabel *textLabel13 = [UILabel new];
    [midContainer2 addSubview:textLabel13];
    [textLabel13 mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];
    

虽然完成了布局,但是很不容易从代码看出视图的层级关系,日后维护的时候就不是很方便了.

改用复合内联表达式后的布局代码如下:

    UIView *outView = ({
        UIView *view = [UIView new];
        
        UIView *midView1 = ({
            UIView *view = [UIView new];
            
            UILabel *textLabel = ({
                UILabel *label = [UILabel new];
                //config your label
                label;
            });
            [view addSubview:textLabel];
            [textLabel mas_makeConstraints:^(MASConstraintMaker *make) {
                //layout code
            }];
            
            view;
        });
        [view addSubview:midView1];
        [midView1 mas_makeConstraints:^(MASConstraintMaker *make) {
            //layout code
        }];
        
        UIView *midView2 = ({
            UIView *view = [UIView new];
            
            UILabel *textLabel1 = ({
                UILabel *label = [UILabel new];
                //config your label
                label;
            });
            [view addSubview:textLabel1];
            [textLabel1 mas_makeConstraints:^(MASConstraintMaker *make) {
                //layout code
            }];
            
            UILabel *textLabel2 = ({
                UILabel *label = [UILabel new];
                //config your label
                label;
            });
            [view addSubview:textLabel2];
            [textLabel2 mas_makeConstraints:^(MASConstraintMaker *make) {
                //layout code
            }];
            
            view;
        });
        [view addSubview:midView2];
        [midView2 mas_makeConstraints:^(MASConstraintMaker *make) {
            //layout code
        }];
        
        view;
    });
    [self.view addSubview:outView];
    [outView mas_makeConstraints:^(MASConstraintMaker *make) {
        //layout code
    }];

可以看出层级关系清晰了.并且带来了额外的2个好处:

1.视图之间的耦合度降低了.此时可以复制任意一个内联表达式中包含的代码到其他位置,而不会引起布局错误.

2.不需要绞尽脑汁思考如何命名了,内联复合表达式中的命名因为作用域的关系没有冲突了.

 

然后我们尝试在swift中也使用复合内联表达式

哦噢,报错了

这说明swift不支持复合内联表达式.bigView在swift中被编译器认为是一个代码块.

但是我们又想使用这种语法带来的好处,怎么办呢?

我们可以利用IIFE来模拟. http://weizhifeng.net/immediately-invoked-function-expression.html

        ({
            let view = UIView()
            contentView.addSubview(view)
            view.backgroundColor = .green
            view.snp.makeConstraints({ (m) in
                m.edges.equalTo(contentView).inset(UIEdgeInsetsMake(3, 3, 3, 3))
            })
            
            ({
                let label = UILabel()
                label.backgroundColor = .red
                label.textColor = .white
                self.label = label
                view.addSubview(label)
                label.snp.makeConstraints({ (m) in
                    m.center.equalTo(view)
                })
            })()
            
        })()

关键在于尾部的括号!

 

posted @ 2017-05-22 16:53  ashamp  阅读(358)  评论(0编辑  收藏  举报