Today's blog content on the system to discuss the impact of masonry on FSP, and how to better use the masonry. If you are familiar with iOS development, then you should not be unfamiliar with the masonry framework. Simply put, the birth of masonry makes AutoLayout more elegant to use, making the layout of the control more convenient. When you look at a thing with a dialectical perspective, there are two sides to everything, and the use of masonry is no exception. Improper use of the masonry framework will directly affect the FPS of the UI. Today we're going to discuss some of the pitfalls of using masonry and look at how they affect performance. This blog we will still rely on the demo to describe some of the things.
Before writing an article is specifically to introduce the masonry framework, and the framework of the source of the relevant analysis, the details please step in the "iOS development of the masonry framework source code Analysis ."
First, the demo summary
1. Operation effect
Preconceived, the content of this blog is still based on our specially designed for this blog to build the demo, first of all, we first look at the demo how to run the effect, through the demo we can see those problems, and how these problems are solved. Below is the result of the demo that we are involved in this blog post.
From the bottom of the running effect is not difficult to see, we are divided into 6 cases to observe and judge how the various uses of masonry on the impact of FPS . Over six Segmentcontrol can be used to switch the cell layout. Of course, each layout is represented by the same cell. This is also the principle of keeping the experimental item in line with the other items while doing the experiment. We can use the lower right FPS indicator to intuitively feel the trend of FPS changes. Below this FPS display control is taken from our previous demo. The previous demo was also about FPS optimization, but it is about FPS optimization for cell height dynamic computing, and for details, please visit theUI fluency analysis of the various cell-highly adaptive implementations of iOS development .
The data displayed in the cell below is randomly generated, and the image on the left is randomly taken. The title and detail on the right are nsattributedstring and some detail below are likely to be empty. If the detail of one of the bars is empty, then the layout of all the content below the detail is moved up. The demo and its technical points will be described in more detail later.
2. Analog Network Request
The data shown in the cell above is obtained by simulating network data, and below is the code for our simulated network layer. After all, is the demo, and the focus of the demo is not on the network layer, the bottom of the simple to write a bit, the code is relatively simple. is a singleton + a random generation method of simulation data, and then the randomly generated data through the block callback to the network layer of users. The specific code looks like this:
3, the above cell base class Xbasetableviewcell
The cells in each of the above segment are a separate cell type, but these cells have a common parent class. This parent is responsible for dealing with the logic that these cells share. The Xbasetableviewcell below is the base class for all the cells shown above. All controls on the cell are declared and initialized. and provides a method for setting the value.
It is not difficult to see from the code below that there are two methods that need to be overridden by subclasses, one is to add layout to the control addlayoutsubviews, and the other is to update the layout of the method Updatelayoutsubviews method. Both methods are overridden in each subclass and given a different layout.
4. Switch cell code in segment
Below is the corresponding VC in the click segmentcontrol Logic Code, click on the different segment will choose a different cell and then refresh TableView, the code is relatively simple do not do too much to repeat.
Second, the above-mentioned various layout methods analysis
The next thing to do is to analyze the impact of each layout on the FSP, which will be analyzed using instrument for different layout situations and look at the specific data. The following sections discuss update operations using only masonry, remake operations, make after update, frame operations, and make after frame operations.
1. Update
First, let's look at the update operation. That is, using update to assign a value directly to the control is a lazy operation. Because the UI layout of some controls is updated when we set the cell's value in our demo, we simply add the constraint directly to the control using masonry's update. One feature of the update operation in masonry is that the update constraint finds the constraint in the added constraint array first, and then updates the constraint, adding the appropriate constraint if the install is not found. The function of this update is relatively low in terms of efficiency.
I can first look at the code implementation, in subclass Xupdatelayouttableviewcell , rewrite the addlayoutsubviews and updatelayoutsubviews two methods. In the Updatelayoutsubviews method, add a constraint for all controls using update. The following write will invoke the Updatelayoutsubviews method below each time the value is set, which will update all the layout of the control on the cell, but it is not recommended, as it will update the constraints that do not need to be updated. The reason for listing today is that there is a real problem in the bottom of the development, perhaps because of the time constraints, perhaps because of other causes of this code implementation.
Let's use instruments to run the demo above, and then intuitively feel the visual representation of the demo's core animation. Below is the FPS data we will use to switch the Segmentcontrol to update. From the data below, it is not difficult to see that adding an update constraint directly with update is a comparison that affects FPS. Of course, the property string is also used in the cell, which we'll discuss later.
We can come and run. Time profile in the update state. As shown below, it is not difficult to see from the results below that a two-block operation is time-consuming when the cell updates data. One is the masonry update operation, and the other is the label setting nsattributedstring operation. Because each label we use assigns a property string, this is a more time-consuming operation. Another thing to make it clear is that the creation and generation of property strings does not take much time, and that the assignment and rendering of property strings is more time consuming, which is not difficult to see in the timeline below.
2, remake
Next we look at the remake operation, from the bottom of the core animation results are not difficult to see, its performance is not as good as using the update operation. Below the FPS is lower than the update, which is also related to the operation of remake itself, remake in the literal sense is a re-production, if you have already added the constraint before the first remove, and then add a new constraint.
Below is the time profile for remake, which we can see from the results that the layout update takes up to 66.6%, and that 33% of the install time consuming uninstall takes up about 10% of the overhead. The remake efficiency is the lowest in masonry. We will continue the discussion later.
3. Make + update
After discussing update and remake, let's discuss the general practice of using masonry. is to use make to initialize the layout of the control, using update to update the constraints that need to be updated. Because the code is relatively simple, it will not be affixed to the top, but it is necessary to run a instrument run for a bit. Below is the result of make + update in the way that core animation ran out. However, from the results of the FSP below, it is better to use only the update or remake effect, but the lower FPS is still not high, and later we will refine the data below.
The time profile in this section does not run, because we still use the update constraint when setting the value, but instead of updating all the constraints, we update the ones that only need to be updated. Because the amount of updated constraints will be less, all FPS performance will be better than the previous update of all constraints. Make + update will be slightly improved FPS, but from the diagram below we can see that the improvement is not particularly good.
4. Frame + Frame
Next, we don't have to masonry the layout, we use the frame layout directly. Since AutoLayout will eventually be converted to a frame layout, it is clear that the frame layout is better than the AutoLayout layout in terms of performance. Next we'll use the frame layout and then use the frame update. The FPS below is reasonable, but not full, most of the reason is because of nsattrubitedstring.
We can look at the time profile of the updated frame as shown below. From below, it is not difficult to see that the time ratio of the update frame accounts for only 2.5%, before the update constraint can account for about 60% , you can see the benefits of using the frame layout. It is not difficult to see from the analysis results below that the main factors affecting FPS have been transformed from the update layout to the AttributeString setting. This is why the FPS is not full.
6. Make + frame
The birth of masonry is to facilitate the layout of the control, the frame layout is not flexible enough to fit together more cumbersome, so only the AutoLayout. However, although AutoLayout can be easily adapted to the screen, its performance is not particularly good. So can we combine the two? That is, use make to initialize the layout of the control, and use frame to update the layout. Of course, this process is not simple to update the frame when setting the value, because it is useless to update the frame when the cell set the value, because after the frame is updated, it will be displayed in the layout of the AutoLayout when it is rendered. What we need to do is put the frame layout behind the AutoLayout layout, and all we have to do here is put the relevant code for the updated frame into the next runloop to execute. Update the frame code as follows:
In the cell is make to initialize the control layout, use frame to update the layout, and frame+frame the same way, just use the masonry layout, when the first screen loading is not as good as the frame layout, later updates are the same. Below is the result of the core animation using the Masonry+frame form. The effect is slightly worse than the last part, but the final effect is full OK.
Iii. Summary
This blog only discusses the masonry of the layout of the impact of FPS, as to the above-mentioned nsattributestring The problem is not too much to repeat. If there are many rich text presentations that affect FPS, depending on your business needs, there are other ways to optimize it, such as using the relevant node that Asyndisplaykit provides for display, and so on. At the end of the blog, it is necessary to make a summary.
Below is our more granular data in the code, it is not difficult to see remake performance is the worst, so we use masonry as far as possible to use less remake. It is not a good choice to update the control only blindly, and if you want to use the masonry framework to make layout updates to the controls, it is best to separate the invariant constraints from the ones that need to be updated. Use make to add related constraints and use Update to modify the constraints that need to be updated. Of course, the performance of the frame layout is better, but the layout process is too cumbersome to fit the screen. Of course, you can use masonry to layout the layout of the update, of course, it is important to note that the timing of the frame layout update, need to AutoLayout loading time.
Below is a unified data statistics, of course, for this blog is the corresponding demo. The table below is the average time to update the different ways in which the cell layout was updated, from the data below we don't look ugly. Coarse remake update layout takes up the most, consumes 12+ms, and update all constraints time is also a lot, one update layout used 9+ms. Instead of updating only the layouts that need to be updated, 7+ms is a little better than updating all layouts. Of course, directly modify the frame when the use of the least, only 0.06+ms time, from the data can be intuitive to feel the efficiency of the frame layout.
And the right side of the creation and assignment of a property string, where we can see that the creation of the property string is not too much time, and the comparison time is the property string assignment, each assignment takes up 0.7ms, if it is 10, then the assignment time is 7ms, if the content of the property string is more complex, then it will certainly be higher than this. Of course we can use some of the controls and methods provided by third parties to optimize this part of the time, which can be discussed later.
Today's blog is here, the purpose is to use masonry reasonable use, if necessary, you can use frame for layout.
Above Demo-github Share Link: https://github.com/lizelu/FPSProfileDemo
iOS development for the FPS optimization discussion under masonry