In-depth analysis of the Masonry framework source code for iOS development, and the iosmasonry framework source code

Source: Internet
Author: User

In-depth analysis of the Masonry framework source code for iOS development, and the iosmasonry framework source code

MasonryIt is a lightweight framework that iOS often uses in the control layout. Masonry makes NSLayoutConstraint easier to use. Masonry simplifies the use of NSLayoutConstraint, allowing us to specify constraints for our controls in a chained manner. The topic of this blog is not to teach you how to use the Masonry framework, but to parse the source code of the Masonry framework, so that you can understand how Masonry encapsulates NSLayoutConstraint, what is the role of each part of the Masonry framework. In the Masonry framework, there are still many good tastes. The Masonry framework is in the Objective-C version. If your project is in the Swift language, you must use the SnapKit layout framework. SnapKit is actually the Swift version of Masonry. Although the two have different implementation languages, their implementation ideas are basically the same.

Today, the blog's idea of parsing the source code of the Masonry framework is to first compare the difference between the use of Masonry and the system native when adding the same constraints to a View. Next, let's take a look at the class diagram of the main part of the Masonry framework. From the class diagram, we will analyze the structure of the Masonry framework as a whole. Then, from the whole to the part, we will gradually refine and explore its internal implementation details. Through the above steps, we will have a detailed understanding of the internal implementation of the Masonry framework. In fact, the Masonry framework is lightweight, and there is not much upstream source code in total. However, you can still learn a lot of practical things by carefully reading the implementation details.

First, Masonry's address on github is a https://github.com/SnapKit/Masonry, And you can Clone it to the Masonry framework through the above link, including the introduction of the Masonry framework and some examples of using Masonry. The usage of Masonry is not described too much in today's blog. For details about how to use it, refer to the link on github. Today, we will analyze the source code of the Masonry framework.

 

I. Comparison between the Masonry framework and NSLayoutConstraint call Methods

First, NSLayoutConstraint adds a constraint for our View, and then gives the Masonry code. Of course, here we will not talk about the conciseness of Masonry's constraints. Of course, good things do not need to be publicized. To enter the topic of this part, we need to add a top constraint to a View. The Constraint Relation is represented by an expression as "subView. top = superView. top + 10 ". That is, the top of the Child view and the top of the parent view are separated by 10 pt.

 

1. Use NSLayoutConstraint to add Constraints

The code below adds a Top constraint relative to the superView to the subView. It is not enough for a View to determine the position. Therefore, we need to write multiple constraints below to determine the relative position of a View. In fact, the following is an expression. Each parameter in the NSLayoutConstraint constraint constructor forms an integral part of this expression. From top to bottom, each of our team's parameters is parsed. The constraintWithItem parameter is used to specify the constrained object. Here it is subView. The first attribute parameter specifies the attribute that restricts the object, which is the Top attribute of subView. The relatedBy parameter is used to specify the constraint relationship, for example, greater than or equal to, less than or equal to a constraint value. The toItem parameter specifies the object with relative constraints, which is relatively superView, so the parameter here is superView. The second attribute parameter specifies the Top attribute of superView. Multiplier specifies the multiples of the constraints, while constant specifies the offset of the constraints.

From top to bottom, parameters in the NSLayoutConstraint constraint constructor constitute a mathematical expression, that is, subView. top = superView. top * 1 + 10. This expression intuitively shows the subView. top and superView. top relationship. With the code below, we add a Top constraint to subView, with the offset of the constraint being 10.

 

2. Use Masonry to add the preceding Constraints

Next, we will use Masonry to add the above constraints. The Code is as follows. Three setting methods are provided below. The three methods below are equivalent. Of course, we do not know the three implementation methods below in Masonry. Each sentence in the Block below represents the meaning of subView. top = superView. top * 1 + 10. That is to say, we only need to write one of the three lines of code. The benefits of using Masonry are clear at a glance, making your code more concise.

The Masonry framework supports adding constraints, updating constraints, rebuilding constraints, and implementing basic animations. Powerful functions. In the Masonry framework, chained calls and anonymous closures are used to simplify the addition of constraints. For more details about how to use Masonry, see the Github link of the above Masonry framework. The specific usage will not be described too much here.

 

Ii. Class Structure of the Masonry framework

Through the above Masonry usage, we can see that the UIView object can directly call the mas_makeConstraints method to add constraints for the corresponding View object. Because the mas_makeConstraints method is located in the View + MASAdditions category of UIView, the object of UIView can be called directly. There are other methods in the View + MASAdditions category for the UIView object. We will introduce them in detail later.

Below is the relationship between the core classes of the Masonry framework and categories. The class diagram below is drawn when reading the Masonry source code. This is only one copy. If there is similarity, it is a coincidence. If the text in is relatively small, you can save the image to a local location, and then zoom in to view it. To put it bluntly, go to the topic of our class graph. The class diagram below does not contain all the classes in the Masonry framework, but all the core classes are below. We explain the class diagrams from left to right.

1. View + MASAdditions category introduction (in the red box on the left)

The leftmost part is the section in the green box, which is the public category of the UIView of the Masonry framework, that is, the section of View + MASAdditions in the source file, in this category, the member attributes of the MASViewAttribute type are added. (We will introduce masviewattri as a magic horse ). In addition to adding a series of member attributes, the mas_closestCommonSuperview method also adds four public methods: The mas_closestCommonSuperview method is used to find the nearest public parent view of two views (similar to the minimum public multiple of two numbers) the mas_makeConstraints method is responsible for creating installation constraints, the mas_updateConstraints is responsible for updating existing constraints (if the constraint does not exist, Install), and The mas_remakeConstraints method is responsible for removing the original constraints and adding new constraints. The above method is the main method for calling the UIView object setting constraints. The implementation method will be detailed later.

 

2. Introduction to the MASViewAttribute class (in the yellow box on the right)

This section describes the public categories of UIView that users can directly use. Next, let's take a look at what users cannot see, which is the right of the class diagram below. The coupling of the four small classes on the right is relatively high. Let's take a look at the MASViewAttribute class first. The MASViewAttribute class has a simple structure, including three attributes and three methods. We can see from the MASViewAttribute class name that this class encapsulates UIView and NSLayoutAttribute. The equation is used to represent MASViewAttribute = UIView + NSLayoutAttribute + item. The view attribute in the MASViewAttribute class indicates the constrained object, and item is the part of the object that can be constrained.

The item member attribute here will be used as a parameter for constraintWithItem and toItem in the NSLayoutConstriant constriant constructor later. Of course, for UIView, this item is the UIView itself. For UIViewController, the output Item is topLayoutGuide. bottomLayoutGuide will give a detailed introduction later. Besides the constructors, this class also has an isSizeAttribute method to determine whether the layoutAttribute in the MASViewAttribute class is NSLayoutAttributeWidth or NSLayoutAttributeHeight. If it is Width or Height, then the constraint is added to the current View instead of the parent View.

 

3. Introduction to MASViewConstraint(Part of the yellow box on the right)

Next, let's take a look at the MASViewConstraint class, which further encapsulates the NSLayoutConstriant class. One of the core tasks of MASViewConstraint is to initialize the NSLayoutConstriant object and add the object to the corresponding view. Because NSLayoutConstriant requires NSLayoutAttribute and the restricted View during initialization, and MASViewAttribute is the encapsulation of View and NSLayoutAttribute, The MASViewConstraint class depends on the MASViewAttribute class. The relationship between the two is as follows.

The following class diagram shows that MASConstraint is the parent class of MASViewConstraint. MASConstraint is an abstract class and cannot be instantiated. We can regard MASConstraint as an interface or protocol. The MASConstraint abstract class also has a subclass, that is, MASViewConstraint's sibling class MASCompositeConstraint. From the name of MASCompositeConstraint, we can see that MASCompositeConstraint is a combination of constraints, that is, it stores a series of constraints. The structure of the MASCompositeConstraint class is relatively simple. Its core is an array that stores MASViewConstraint objects. MASCompositeConstraint is an encapsulation of the array.

 

4. Factory MASConstraintMaker (in the middle green box)

After reading the data on both sides, let's take a look at the middle part, that is, the MASConstraintMaker class. This class is a factory class that is responsible for creating objects of the MASConstraint type (dependent on the MASConstraint interface, rather than the specific implementation ). In the View + MASAdditions category of UIView, some methods in the called MASConstraintMaker class are called. When we use Masonry to add constraints to subView, the Block parameter in the mas_makeConstraints method is the object of MASConstraintMaker. You can use the MASConstraintMaker object called back by the Block to specify the constraints to be added to the View and the value of the constraints. The constraints attribute array in the factory records all the MASConstraint objects created in the factory.

The core classes in the Masonry framework and the relationship between categories are described. The following figure shows the class diagrams of the core classes and categories. The following will gradually explore its code implementation.

 

Iii. View + MASAdditions source code parsing

We first parse the source code in the public category View + MASAdditions of UIView, that is, the section corresponding to the red box above. The user adds constraints to the View through the View + MASAdditions, that is, the View + MASAdditions is the channel through which the Masonry framework interacts with the outside world. This section mainly analyzes the View + MASAdditions source code, first introduces its member attributes, and then introduces the main methods. Enter the topic of this part.

1. View + MASAdditions main member attributes and getter Method

The lower part is the member attributes in the View + MASAdditions category. Others are similar to the lower part. These attributes are of the masviewattritions type. The following mas_left member attribute is used as an example. Because MASViewAttribute is the combination of View and NSLayoutAttribute, mas_left represents the nslayoutbuteleft attribute of the current View, that is, mas_left stores the nslayoutattriattributeleft attribute of the current View. Similarly, mas_top represents the NSLayoutAttributeTop attribute of the current View, and the attributes of other members are the same.

Through the getter method corresponding to the above Member attributes, we can clearly understand the content stored in it. Below is the getter method corresponding to the attributes of the mas_left, mas_top, and mas_right members. What we do is to instantiate the masviewattivity and specify the LayoutAttribute corresponding to the current view during instantiation. That is, mas_left = self + NSLayoutAttributeLeft, mas_top = self + NSLayoutAttributeTop. Of course, the self here represents the current view.

 

2. mas_makeConstraints method Parsing

As mentioned above, you can add constraints to the current view by calling the mas_makeConstraints method. The code below is the implementation of the mas_makeConstraints Function Code. According to my personal understanding, I have commented on each line of code. Next, let's take a good look at the structure of this function. the Return Value of the mas_makeConstraints method is an array (NSArray), which stores all the constraints added in the current view. Because the Masonry framework encapsulates NSLayoutConstraint as a MASViewConstraint, all objects stored in the array here are MASViewConstraint objects.

Next, let's take a look at the mas_makeConstraints parameter. The mas_makeConstraints test parameter is an anonymous Block (that is, an anonymous closure) of the void type (^) (MASConstraintMaker *), and the return value of this closure is Void, and an object of the MASConstraintMaker factory class is required. The function of this closure is to let the mas_makeConstraints method use this block to initialize the MAConstraint attribute in the MASConstraintMaker factory class object. Please use the block below.

In the mas_makeConstraints method body, first set the current View's translatesAutoresizingMaskIntoConstraints attribute to No, and then create a MASConstraintMaker factory class Object constraintMaker, then, the constraintMaker object is called back to the user through the block so that the user can initialize the MAConstraint type attribute in constraintMaker. In other words, what the block is doing is that the user sets the constraints to the added code, such as make. top (@ 10) = (constraintMaker. top = 10 ). Finally, call the install method of constraintMaker to install the constraints specified by the user.

  

 

 

3. Analysis of mas_updateConstraints and mas_remakeConstraints Functions

The internal implementation of these two functions is similar to that of mas_makeConstraints, that is, setting an additional attribute. In mas_updateConstraints, set updateExisting in constraintMaker to YES. In other words, when adding constraints, you must first check whether the constraints have been installed. If they are added, they are updated. If they are not added, they are added. In mas_remakeConstraints, The removeExisting attribute is set to YES, which means that the old constraints on the current view are removed and new constraints are added.

  

  

 

4. Analysis of the mas_closestCommonSuperview Method

The mas_closestCommonSuperview method is used to calculate the public parent views of the two views. This is similar to finding the minimum public multiples of the two numbers. The code below is to find the public parent view of the two views, of course, the closest public parent view. If yes, nil is returned. If no, nil is returned. Searching for the public parent view of the two views is very important for adding constraints, because the relative constraints are added to the public parent view of the two views. For example, give a column named viewA. left = viewB. right + 10. Because it is a relative constraint between viewA and viewB, the constraint is added to the public parent view of viewA and viewB. If viewB is the parent view of viewA, then the constraint is added to viewB to constrain viewA.

  

 

4. cloudification and restriction on factory MASConstraintMaker

In the previous section, we analyzed the View + MASAdditions category. In this category, we mainly used the constrained factory class MASConstraintMaker. Next we will look into the content in MASConstraintMaker. MASConstraintMaker is a constraint factory class because MASConstraintMaker creates NSLayoutConstraint objects with a value assignment. Because Masonry further encapsulates the NSLayoutConstraint class into MASViewConstraint, MASConstraintMaker is responsible for creating MASViewConstraint objects, call the Install method of the MASViewConstraint object to add the constraint to the corresponding view.

1. core public attributes in MASConstraintMaker.

Below are some attributes in MASConstraintMaker. We can see that all the attributes below are of the MSAConstriant type, and MSAConstriant is an abstract class. Therefore, the member variables below are essentially objects of the MSAConstriant subclass MASViewConstraint. MASConstraintMaker is responsible for instantiating MASViewConstraint. In one sentence, MASViewConstraint, MASViewConstraint = View + NSLayoutConstraint + Install. The detailed implementation of MASViewConstraint will be provided later. There is also a private array constraints in MASConstraintMaker, which is used to record and create a Constraint object.

  

 

2. parsing factory methods in MASConstraintMake

The factory class must have a factory method. Next we will introduce the factory method in MASConstraintMaker. Each attribute of the MASConstraint type corresponds to a getter method, and the addConstraintWithLayoutAttribute method will be called in the getter method, addConstraintWithLayoutAttribute will call the method in the second screenshot graph. The method in is the factory method of the MASConstraintMaker factory class. MSAViewConstraint object is created based on the provided parameters, if the first parameter of the function is not empty, the newly created MSAViewConstraint object and the parameter are combined into a MASCompositeConstraint class (MASCompositeConstraint is essentially an array of MSAViewConstraint objects.

Below is the factory method of the MASConstraintMaker factory class, which is responsible for creating objects of the MASConstraint class. The following methods can be used to create MASCompositeConstraint and MASViewConstraint objects. As mentioned above, the MASCompositeConstraint object is an array of the MASViewConstraint object. After the corresponding objects of the MASConstraint class are created below, the created object is added to the private constraints array of the MASConstraintMaker factory class to record all constraints created by the factory object. NewConstraint. delegate = self; this statement is very important. Because a proxy is set for the MASConstraint object, chained calling is supported (for example, maker. top. left. right. similar to (@ 10 )).

Take maker. top. left. right as an example. The maker here is our MASConstraintMaker factory object. maker. top will return the MASViewConstraint class object with the NSLayoutAttributeTop attribute. Let's first make a conversion: newConstraint = maker. top. Then maker. top. left is equivalent to newConstraint. left, it should be noted that the left method called at the moment is not the left getter method in our factory MASConstraintMaker, but the getter method of the left attribute in the MASViewConstraint class. The newConstraint setting proxy is used to call the factory method of the MASConstraintMaker factory class in the MASViewConstraint class to complete the creation. If the following code does not have newConstraint. delegate = self; proxy settings, chained calling is not supported.

To sum up, if you call maker. top, maker. left and so on. All these methods call the factory method below to create the corresponding MASViewConstraint object and record it in the constraint array of the factory object. A chained call is to specify the current factory object as the proxy of the MASViewConstraint object. Therefore, a MASViewConstraint object can call the factory method through a proxy to create another MASViewConstraint object, the proxy mode is used here.

 

3. install method in the factory class

Although we regard MASConstraintMake as a factory class, the function of this factory class not only creates the MASConstraint object, but also calls the install method of the MASConstraint object to install the corresponding constraints on the desired view. In the MASConstraintMake class, the install method traverses all the Constraint Objects Created by the factory object and calls the install method of each constraint object to install the constraint. Below is the install method in the factory class.

When installing constraints, if self. removeExisting = Yes, you can use the install method called by the mas_remakeConstraints method to remove the original constraints and then add new constraints. When installing constraints, assign updateExisting to each constraint. Each constraint determines whether to update when calling its own install method. Below is the implementation and comments of the install method of MASConstraintMake.

  

 

5. Continue to explore MASViewConstraint

The object created by the MASConstraintMaker factory class is essentially an object of the MASViewConstraint class. The MASViewConstraint class is essentially an encapsulation of MASLayoutConstraint. Furthermore, MASViewConstraint is responsible for organizing parameters for the MASLayoutConstraint constraint constructor, creating the MASLayoutConstraint object, and adding the object to the corresponding view. Next, we will parse the content in the MASViewConstraint class.

1. Exploration of object chained call of MASViewConstraint

MASViewConstraint objects support chained calling, such as constraint. top. left. similar to (superView ). offset (10); the above method is chained call, and the form of similar to (superView) is not the method of function call in Objective-C, in Objective-C, the function is called through [], and () is used here (). Next we will analyze how this chained call is implemented.

In the MASViewConstraint class, the left, top, and other constraints of the getter method will call this method below, in this method, the proxy is used to call the factory method in the factory to create the corresponding MASConstraint object according to LayoutAttribute.

 

How is the call method like offset (10) implemented? We know that methods cannot be called through parentheses in OC. Closure is acceptable over there, but offset () is not a simple closure. After the code analysis of offset (), we can easily find that offset () = offset + (); the Code Implementation of offset is as follows. Offset is the name of a getter method. The return value of the offset function is an anonymous Block, that is, the () behind the offset (). This anonymous closure has a CGFloat parameter. To support chained calling of this anonymous closure, a MASConstraint object is returned.

  

 

2. install method Parsing

In MASViewConstraint, the install method is used to create a MASLayoutConstraint object and add the object to the corresponding View. The following code creates an NSLayoutConstraint object based on the parameters collected by MASViewConstraint in install. The MASLayoutConstraint below is actually the alias of NSLayoutConstraint. The following is the NSLayoutConstraint that calls the system to create the corresponding constraint object. The constructor below is consistent with the NSLayoutConstraint in the first part.

  

After creating the constraint object, we need to find the constraint to add to that View. The following code segment is used to obtain the view that receives the constraint object. If the two views are relatively constrained, the two public parent views are obtained. If Width or Height is added, it will be added to the current view for a long time. If neither a relative view nor a Size constraint is specified, the constraint object is added to the parent view of the current view. The code is implemented as follows:

    

 

After creating the constraint object and finding the view that hosts the constraint, add the constraint to the view. When adding a constraint, we need to determine whether the constraint is updated. If the constraint is updated, we need to first obtain the existing constraint and update the constraint, if the updated constraint does not exist, add it. After successful addition, we will use the mas_installedConstraints attribute to record the constraints of this installation. Mas_installedConstraints is an NSMutable attribute associated with UIView during runtime. It is used to record all constraints that constrain the view.

  

 

3. UIView + MASConstraints, private category of UIView

In MASViewConstraint, the private category UIView + MASConstraints of a UIView is defined. This function is used by UIView to associate a NSMutableSet-type mas_installedConstraints attribute through runtime. This attribute records all constraints that constrain the View. The code is implemented as follows.

 

Due to limited space, today's blog is here first. The code in the Masonry framework cannot be described in this blog. However, I shared a Masonry Demo and source code parsing project on github. The key code of Masonry is described and commented out. Below is the github sharing link.

Github address: https://github.com/lizelu/MasonryDemo

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.