background

When A page of Kuaishou App was native, A customized waterfall layout was adopted to display card A and card B below it. Due to time and labor costs, existing layout classes in the project were reused in the initial development. Since the layout does not support adaptive item width and height, the dimensions of all items need to be calculated immediately after the data is returned, which seriously slows down the loading of the data on the first screen. Therefore, it is necessary to increase the ability to adapt item size to the layout, disperse the calculation pressure of the layout, and speed up the rendering of the A-card on the first screen.

The problem

After the optimization into the version, some developer students (non-working areas) reported that the page on iOS15 met the inevitable crash, as shown inUICollectionViewRecursive calls_updateVisibleCellsNowLead to the final stack burst. However, the problem was never replicated locally by the author, nor was the beta package output by the build platform.

positioning

According to the feedback of the developer, after pulling the code of the latest development branch, I began to encounter the crash of the page being jammed and the stack bursting. The starting point and end point of stack records are both in the system method. From the naming of stack burst method, we guess that there is a problem in the layout display of item. Since this page is calculated when the optimization point of this issue is to delay the layout of A card item to display, it is speculated that there may be A problem with the estimated height set. After communicating with the feedback students and trying to adjust the problem point, crash still existed and there was no change in stack, so the reason for improper setting of estimated height was excluded.

After searching the relevant description of this problem online, only one or two feedback with similar performance were found. The problem point was that when dynamically measuring the size of item, stable frame information could not be obtained all the time, so collectionView always tried to measure and finally burst the stack. Therefore, it was speculated that there might be something wrong with the constraints of CARD A. Unable to get the size of the problem causes the frame to keep changing. After the feedback students were asked to adjust the problem point again, crash still existed and the stack remained unchanged, and the size of card A returned to the same width and height after the first measurement, so the above problem point was eliminated.

In the validation of the above two possible problems, the local branch, cut into the feedback students found that the other crash problems appeared on the branch, but just before the branch is not the crash, so doubt its branch environment itself is flawed, affecting the page display, but the feedback from students after the switch to the latest development branch, The problem can still be stably reproduced, indicating that the problem is not related to the branch environment, so the possible influence of the branch environment is excluded.

Since the author did not locally report the specific device (iPhone11 iOS15.0.2) where the student encountered the problem, and the debug package and beta package could not be reappeared, it was suspected that there might be something wrong with the device itself (there was a 7Plus in the QA department of the author’s work area that could not be debugged locally, but the beta package could run). After inquiring in a large group, it was found that other developers were also experiencing this problem, so the possibility that the specific device was wrong was ruled out.

After borrowing the faulty device and running the debug package, the author found that it still could not be reproduced locally. After comparing the whole development environment, it was found that all the students who encountered problems used Xcode13 for development. The baler used by the author locally and on the construction platform was Xcode12, so it was suspected that the problem was introduced by Xcode13. After upgrading Xcode13, the author was able to reproduce locally, thus confirming that the problem was related to the Xcode version.

repair

Since the focus of this page optimization is to disperse the full A card layout in advance, the item highly adaptive logic of UICollectionViewLayout is reused on the premise of keeping the minimum changes, and its specific interaction logic is as follows:

Due to the use of the waterfall flow layout inherited from UICollectionViewFlowLayout, to open the item highly adaptive, need in the initial layout to set up a forecast height (estimatedItemSize), Used to calculate the number of items and layout that the collectionView can display for the first time. After item is populated with data, Layout will be called preferredAttributedsFitting: method and through the item systemLayoutSizeFittingSize: withHorizontalFittingPriority: verticalFitting Priority: the size of the method to get the latest, and according to the size to adjust the layout of the item information (UICollectionViewLayoutAttributes).

The page as A whole is composed of A card list at the top and A double-column B card list at the bottom. The content of A card is highly dynamic, so its height is automatically expanded according to the data through automatic layout, while the content of B card is relatively fixed, so the specific height can be calculated in advance. The optimization of the implementation, then by rewriting A card item systemLayoutSizeFittingSize: withHorizontalFittingPriority: verticalFittingPriority: method to take over the management of the system default is calculated.

Method by observing preferredAttributedsFitting: after the output on the two Xcode version, found that A single A card after measuring the size, can return to the stability of the frame information, but the double column B card is different.

The A card is the size calculated by the constraint layout, and its frame is always within the bounds of the collectionView, so there is no infinite stack explosion.

B card is by manual calculation and wide high size, by default preferredAttributedsFitting: realize the frame will be beyond the bounds of collectionView attributed. B card in Xcode12 preferredAttributedsFitting: after the access to the frame is beyond the bounds of collectionView, will continue to use the original attributed, to give up their new attributed, This allows you to render directly after measuring the number of visible cells.

But Xcode13 preferredAttributedsFitting B card: in the access to the frame was beyond the bounds of collectionView, will repeat calls preferredAttributedsFitting:, lead to the final detonation stack.

Once the problem is located, perform each step of the layout by combing out the layout (see Figure 2), After finish call preferredAttributedsFitting: can see collectionView invokes shouldInvalidateLayout: method to do further control layout, decide whether to update the layout information. This fix overrides the method to return YES for the A card item that really needs to be rearranged, and NO for the B card item that has A fixed size. Add judgment, run again, the page display normal, no longer appear stack burst crash.

conclusion

Because this problem only appeared in the new version of the development tool, it could not be reappeared and located in time. In subsequent development, if you encounter a similar problem that cannot be reproduced locally, you should consider the development environment itself as a possible factor causing the problem and adapt it as soon as possible.

Hi, I’m Kaso.Lu from Kuaishou E-commerce

Kuaishou e-commerce wireless technology team is recruiting talents 🎉🎉🎉! We are the core business line of the company, which is full of talents, opportunities and challenges. With the rapid development of the business, the team is also expanding rapidly. Welcome to join us and create world-class e-commerce products together

Hot job: Android/iOS Senior Developer, Android/iOS expert, Java Architect, Product Manager (e-commerce background), Test development… Plenty of HC waiting for you

Internal recommendation please send resume to >>> our email: [email protected] <<<, note my roster success rate is higher oh ~ 😘