# Masonry [![Build Status](https://travis-ci.org/SnapKit/Masonry.svg?branch=master)](https://travis-ci.org/SnapKit/Masonry) [![Coverage Status](https://img.shields.io/coveralls/SnapKit/Masonry.svg?style=flat-square)](https://coveralls.io/r/SnapKit/Masonry) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ![Pod Version](https://img.shields.io/cocoapods/v/Masonry.svg?style=flat)
**Masonry is still actively maintained, we are committed to fixing bugs and merging good quality PRs from the wider community. However if you're using Swift in your project, we recommend using [SnapKit](https://github.com/SnapKit/SnapKit) as it provides better type safety with a simpler API.**
Masonry is a light-weight layout framework which wraps AutoLayout with a nicer syntax. Masonry has its own layout DSL which provides a chainable way of describing your NSLayoutConstraints which results in layout code that is more concise and readable.
Masonry supports iOS and Mac OS X.
For examples take a look at the **Masonry iOS Examples** project in the Masonry workspace. You will need to run `pod install` after downloading.
## What's wrong with NSLayoutConstraints?
Under the hood Auto Layout is a powerful and flexible way of organising and laying out your views. However creating constraints from code is verbose and not very descriptive.
Imagine a simple example in which you want to have a view fill its superview but inset by 10 pixels on every side
```obj-c
UIView *superview = self.view;
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
]];
```
Even with such a simple example the code needed is quite verbose and quickly becomes unreadable when you have more than 2 or 3 views.
Another option is to use Visual Format Language (VFL), which is a bit less long winded.
However the ASCII type syntax has its own pitfalls and its also a bit harder to animate as `NSLayoutConstraint constraintsWithVisualFormat:` returns an array.
## Prepare to meet your Maker!
Heres the same constraints created using MASConstraintMaker
```obj-c
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
```
Or even shorter
```obj-c
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
```
Also note in the first example we had to add the constraints to the superview `[superview addConstraints:...`.
Masonry however will automagically add constraints to the appropriate view.
Masonry will also call `view1.translatesAutoresizingMaskIntoConstraints = NO;` for you.
## Not all things are created equal
> `.equalTo` equivalent to **NSLayoutRelationEqual**
> `.lessThanOrEqualTo` equivalent to **NSLayoutRelationLessThanOrEqual**
> `.greaterThanOrEqualTo` equivalent to **NSLayoutRelationGreaterThanOrEqual**
These three equality constraints accept one argument which can be any of the following:
#### 1. MASViewAttribute
```obj-c
make.centerX.lessThanOrEqualTo(view2.mas_left);
```
MASViewAttribute | NSLayoutAttribute
------------------------- | --------------------------
view.mas_left | NSLayoutAttributeLeft
view.mas_right | NSLayoutAttributeRight
view.mas_top | NSLayoutAttributeTop
view.mas_bottom | NSLayoutAttributeBottom
view.mas_leading | NSLayoutAttributeLeading
view.mas_trailing | NSLayoutAttributeTrailing
view.mas_width | NSLayoutAttributeWidth
view.mas_height | NSLayoutAttributeHeight
view.mas_centerX | NSLayoutAttributeCenterX
view.mas_centerY | NSLayoutAttributeCenterY
view.mas_baseline | NSLayoutAttributeBaseline
#### 2. UIView/NSView
if you want view.left to be greater than or equal to label.left :
```obj-c
//these two constraints are exactly the same
make.left.greaterThanOrEqualTo(label);
make.left.greaterThanOrEqualTo(label.mas_left);
```
#### 3. NSNumber
Auto Layout allows width and height to be set to constant values.
if you want to set view to have a minimum and maximum width you could pass a number to the equality blocks:
```obj-c
//width >= 200 && width <= 400
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400)
```
However Auto Layout does not allow alignment attributes such as left, right, centerY etc to be set to constant values.
So if you pass a NSNumber for these attributes Masonry will turn these into constraints relative to the view’s superview ie:
```obj-c
//creates view.left = view.superview.left + 10
make.left.lessThanOrEqualTo(@10)
```
Instead of using NSNumber, you can use primitives and structs to build your constraints, like so:
```obj-c
make.top.mas_equalTo(42);
make.height.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(50, 100));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 0, 10, 0));
make.left.mas_equalTo(view).mas_offset(UIEdgeInsetsMake(10, 0, 10, 0));
```
By default, macros which support [autoboxing](https://en.wikipedia.org/wiki/Autoboxing#Autoboxing) are prefixed with `mas_`. Unprefixed versions are available by defining `MAS_SHORTHAND_GLOBALS` before importing Masonry.
#### 4. NSArray
An array of a mixture of any of the previous types
```obj-c
make.height.equalTo(@[view1.mas_height, view2.mas_height]);
make.height.equalTo(@[view1, view2]);
make.left.equalTo(@[view1, @100, view3.right]);
````
## Learn to prioritize
> `.priority` allows you to specify an exact priority
> `.priorityHigh` equivalent to **UILayoutPriorityDefaultHigh**
> `.priorityMedium` is half way between high and low
> `.priorityLow` equivalent to **UILayoutPriorityDefaultLow**
Priorities are can be tacked on to the end of a constraint chain like so:
```obj-c
make.left.greaterThanO
OC-Json转模型Dictionary(Plist嵌套模型)
需积分: 0 108 浏览量
更新于2023-07-05
收藏 459KB ZIP 举报
在iOS开发中,数据交换和存储经常涉及到JSON与模型对象之间的转换。Objective-C(简称OC)作为苹果平台的主要编程语言,提供了多种方式来处理这种转换。本篇文章将深入探讨如何在OC中将JSON数据转化为模型Dictionary,特别是处理Plist文件中的嵌套模型情况。
了解JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript的一个子集,易于人阅读和编写,同时也易于机器解析和生成。在iOS开发中,通常使用`NSJSONSerialization`类来处理JSON数据。
1. JSON到Dictionary转换:
当接收到JSON数据后,可以使用`NSJSONSerialization`的`JSONObjectWithData:options:error:`方法将JSON数据转化为Objective-C的对象。这个方法会尝试将JSON数据转换为一个`NSArray`或`NSDictionary`。例如:
```objc
NSData *jsonData = [NSData dataWithContentsOfURL:url];
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
```
2. 字典到模型对象转换:
转换字典到自定义模型对象通常采用两种方式:KVC(Key-Value Coding)和Mantle框架。
- KVC是Objective-C的一种特性,允许我们通过键值来访问和修改对象的属性。创建好模型类后,可以利用KVC将字典内容赋值给模型对象。
```objc
// 假设有一个Person模型
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
//...
@end
Person *person = [[Person alloc] init];
[person setValue:jsonDict[@"name"] forKey:@"name"];
[person setValue:@(jsonDict[@"age"]) forKey:@"age"];
```
- Mantle是一个轻量级的模型转换框架,适用于JSON和Core Data。使用Mantle,我们需要让模型对象遵循`MTLModel`协议,并提供`+modelWithDictionary:error:`工厂方法。
```objc
@interface Person : MTLModel <MTLJSONSerializing>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
//...
@end
// 在.m文件中实现协议方法
+ (NSDictionary<NSString *, id> *)modelPropertiesByName {
return @{@"name": @"name", @"age": @"age"};
}
// 使用工厂方法
Person *person = [Person modelWithDictionary:jsonDict error:&error];
```
3. Plist文件与嵌套模型:
Plist文件是苹果平台常用的存储方式,它以XML或二进制格式存储数据,可以包含字典、数组、字符串等基本类型以及嵌套的结构。处理嵌套模型时,我们需要递归地将Plist中的数据转换成对应的模型对象。
- 对于字典类型的Plist,可以先将其转换为`NSDictionary`,然后逐个解析其内嵌的字典或数组,调用对应模型的初始化方法。
- 对于数组类型的Plist,可以转换为`NSArray`,遍历数组并根据每个元素的类型创建模型对象。
示例代码(假设Person模型中包含一个Address子模型):
```objc
// 解析Person字典
Person *person = [[Person alloc] initWithDictionary:jsonDict error:&error];
// 解析Address字典
Address *address = [[Address alloc] initWithDictionary:jsonDict[@"address"] error:&error];
// 将Address设置给Person
person.address = address;
```
4. 自定义转换逻辑:
当JSON或Plist中的数据结构与模型对象的属性不完全匹配时,可能需要自定义转换逻辑。这可以通过重写KVC的`setValue:forKey:`或Mantle的`+JSONKeyPathsByPropertyKey`方法来实现。
在OC中处理JSON到模型Dictionary的转换,尤其是面对Plist嵌套模型的情况,需要理解JSON序列化、KVC、Mantle等概念,并根据具体需求进行适当的自定义处理。正确地进行这些操作,可以使数据处理变得更加高效且易于维护。