从入门到精通的 Masonry 教程


🚀 一、Masonry 是什么?为什么还要学?

Masonry 是 iOS 最经典的链式 Auto Layout 库,用来替代苹果的 NSLayoutConstraint 写法。
例如 Apple 原生写法:

NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:view1
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:view2
    attribute:NSLayoutAttributeBottom
    multiplier:1.0
    constant:10];

而 Masonry:

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(view2.mas_bottom).offset(10);
}];

可读性强,代码量少,性能差别极小,因此至今仍大量项目使用。


📌 二、Masonry 语法快速入门(10 分钟掌握)

1. 创建约束

[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.top.equalTo(self.view).offset(20);
    make.width.height.mas_equalTo(100);
}];

2. 常用的 MASViewAttribute

属性 含义
mas_left
mas_right
mas_top
mas_bottom
mas_width
mas_height
mas_center 中心
mas_centerX 水平中心
mas_centerY 垂直中心

📌 三、Masonry 的四种主要写法

1)makeConstraints:只添加不更新

[view mas_makeConstraints:^(MASConstraintMaker *make) { ... }];

2)updateConstraints:只更新已有约束

避免重复添加导致冲突(IMPORTANT!)

[view mas_updateConstraints:^(MASConstraintMaker *make) {
    make.height.mas_equalTo(200);
}];

3)remakeConstraints:先移除所有旧约束再重新添加

适合 UI 状态切换。

[view mas_remakeConstraints:^(MASConstraintMaker *make) { ... }];

4)mas_distributeViewsAlongAxis 水平/垂直均分

[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
               withFixedSpacing:10
                    leadSpacing:15
                    tailSpacing:15];

[views mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.mas_equalTo(20);
    make.height.mas_equalTo(30);
}];

📌 四、常见布局场景(极实用)

1. 居中 + 固定宽高

[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.size.mas_equalTo(CGSizeMake(80, 80));
}];

2. 两个 view 左右排列

[leftView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(self.view).offset(20);
    make.right.equalTo(rightView.mas_left).offset(-10);
    make.centerY.equalTo(self.view);
    make.height.mas_equalTo(40);
}];

[rightView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.right.equalTo(self.view).offset(-20);
    make.centerY.equalTo(self.view);
    make.width.equalTo(leftView); // 等宽
    make.height.mas_equalTo(40);
}];

3. scrollView + container 适配内容高度

(非常容易写错)

[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view);
}];

[self.container mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.scrollView);
    make.width.equalTo(self.scrollView); // 关键
}];

📌 五、Masonry 的原理(大白话)

1. MASViewConstraint / MASLayoutConstraint 是什么?

Masonry 自己实现了一个“包装层”:

  • MASViewAttribute
    只是 view + attribute(例如 view.left)

  • MASViewConstraint
    包含一个或多个 MASLayoutConstraint,是你写的约束逻辑

  • MASLayoutConstraint
    继承自 NSLayoutConstraint,真正被 Auto Layout 使用

你在 Memory Graph 看到一堆 MASLayoutConstraint/MASViewAttribute 不是泄漏,这是正常内存暂存(苹果控件内部也有一堆)。


📌 六、Masonry 内存问题(很多项目踩过)

⚠️ 核心点:Masonry 本身几乎不会泄漏,泄漏几乎都是你 block retain self。

例如:

[self.view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.view).offset(self.someValue); // retain self!!!
}];

虽然普通 block 结束后释放,但 Masonry 会(短暂)持有 maker → maker 持有 constraint → constraint 会持有 items(view) → view 持有 vc
导致 vc 一直释放不了。


🔥 Masonry block 防 retain self 的写法(必须背)

__weak typeof(self) weakSelf = self;
[self.view mas_makeConstraints:^(MASConstraintMaker *make) {
    __strong typeof(weakSelf) self = weakSelf;
    make.top.equalTo(self.view).offset(self.someValue);
}];

但更好的方式是:

✔ 使用 mas_offset 而不是 offset(self.xxx)

make.top.mas_equalTo(self.someValue);

这不会 retain self。
务必降低 block 中 self 的出现频率。


📌 七、Masonry 常见崩溃(高频)

1. 冲突警告:Unable to simultaneously satisfy constraints

原因:

  • 加了重复约束(特别是 height / width)
  • mas_makeConstraints 写了两次
  • 动态更新没用 update而用 make

解决:

  • mas_updateConstraints
  • 切换 UI 时用 mas_remakeConstraints
  • 打印约束 po [view constraintsAffectingLayoutForAxis:...]

2. 视图未添加到父视图就设置约束 → crash

[self.view addSubview:subView];
[subView mas_makeConstraints:...];  // 必须在 addSubview 之后

3. 约束循环依赖,导致布局卡死

例:

make.left.equalTo(label.mas_right);
make.right.equalTo(label.mas_left);

📌 八、Masonry 性能问题

对比原生 NSLayoutConstraint,性能几乎相同。
影响性能的是:

  • 动态频繁 remakeConstraints(避免)
  • scrollView cell 中重复创建约束(最好缓存约束)
  • 在 layoutSubviews 中重新创建约束(禁用!)

📌 九、如何在 Xcode Memory Graph 判断 Masonry 是否泄漏?

你之前问过“为何看到一堆 MASLayoutConstraint/MASViewConstraint 没有看到 view 和 vc?”
解释:

  • MASLayoutConstraint/MASViewConstraint 在 Masonry 内部会短暂存活,用于 layout pass
  • 不是泄漏,因为没有形成 strong reference 循环

判断方法(最可靠):

✔ 看 VC 是否有强引用路径

  1. 打开 Memory Graph
  2. 搜索你的 VC 类
  3. 查看 retain cycle 或 reference chain

如果 VC 被:

  • view
  • view → layer
  • timer
  • block
    等持有 → 才是泄漏

MASLayoutConstraint 本身不会持有 VC(除非你在 block 中用了 self)


📌 十、完整 Masonry 示例(配动画/切换布局)

@interface DemoVC ()
@property (nonatomic, strong) UIView *box;
@property (nonatomic, assign) BOOL expanded;
@end

@implementation DemoVC

- (void)viewDidLoad {
    [super viewDidLoad];

    self.box = [UIView new];
    self.box.backgroundColor = UIColor.redColor;
    [self.view addSubview:self.box];

    [self setupInitialLayout];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggle)];
    [self.view addGestureRecognizer:tap];
}

- (void)setupInitialLayout {
    [self.box mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.height.mas_equalTo(100);
    }];
}

- (void)toggle {
    self.expanded = !self.expanded;

    [self.box mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.height.mas_equalTo(self.expanded ? 200 : 100);
    }];

    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded];
    }];
}

@end

📌 十一、你可能最关心的问题(因为你最近在查内存)

❗ Masonry 是否会导致内存泄漏?

不会
真正泄漏的是:

  • 你在 block 中 retain self
  • 你重复创建 view 却不释放
  • 你把约束持有到 property 中又忘记释放

❗ Masonry 可以 100% 通过 Memory Graph 找到泄漏吗?

  • 可以找到由 block 引起的持有
  • 可以找到视图未释放问题
  • MASLayoutConstraint 不应作为泄漏判断依据

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容