1. Structure and Architecture 1.1 Structure There are two main points in the structure mentioned here: 1. File directory classification 2. Third-party library management 1.1.1 File Directory Classification For ease of management, *** keep the project display directory in Xcode consistent with the actual storage directory In addition, generally classified by business module, the first-level directory can be divided according to MVC format or according to business module Take the most common Model View Controller architecture as an example
1.1.2 Third-party libraries Personal suggestion: If time permits, try to reinvent the wheel yourself. The risk is controllable and the maintenance is good. If not necessary, try not to use the compiled third-party library (framework/.a) directly, and compile the third-party library yourself (safety requirement) There are three ways to manage:
Carthage is recommended here because it is the least invasive to the project and is decentralized management, so there is no need to wait for a long pod update/install process. However, each has its own advantages. Using CocoaPods is simple and crude, and basically does not require any additional settings. It depends on your needs. 1.2 Project Architecture When the project logic is basically centered around a main line, we can use MVC to meet our needs well. However, when the business logic becomes increasingly complex, we can no longer separate the business logic from the code by simply using the Model View Controller programming model, which is called decoupling. In order to better decouple ViewController, the Model View ViewModel programming mode was created. The ViewModel layer actually bridges the Model and ViewController. This mode has advantages and disadvantages. This mode will generate a lot of glue code, but with the responsive programming framework (such as ReactiveCocoa or RxSwift), it can achieve the highest degree of decoupling. A good programming mode is the one that suits the complexity of your actual project business. Extension: <About component-based programming> If the project business is very complex and many business components are common, component-based programming can be used. A common approach is to use CocoaPods to split the project business modules into various pod libraries. You can directly integrate any module you want to use. Combined with MVVM and a responsive programming framework (such as ReactiveCocoa or RxSwift), you can achieve the highest degree of decoupling. 2. Crash & Performance Tuning When the project has completed the business module and launched it, we can start to consider how to improve the user experience of the App. Here are a few examples: 1. Coding standards, regular code review? 2. Can the FPS be maintained at around 60 frames when scrolling a complex list? 3. Can the time spent on page loading and rendering be further reduced? 4. Is network caching done? Are the commonly used static resources of UIWebView/WKWebView cached? 5. Can the startup time of the App be reduced while maintaining minimal business logic? 2.1 UITest & UnitTest When new requirements are developed, we first write UITest and UnitTest before testing to cover the main business process, which can improve the quality of our testing and reduce some visible bugs. In addition, with smoke test cases, the quality of our testing can be improved to the greatest extent (becoming the king of KPI - ????). Moreover, after going online, these unit tests and UITest component scripts can be used in conjunction with automated tests for regular regression testing to improve the quality of the App and reduce the crash rate. 2.2 NullSafe In most cases, when we send a message to an NSNull object, a crash will occur. NSNull objects are common in the data returned by the background, and there may be null fields. Many JSON libraries will convert them into NSNull objects. The following situations will cause a crash:
However, sending a message to a nil object will not cause a crash. For these, you can refer to the processing method in NullSafe and rewrite it. The two methods - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector and - (void)forwardInvocation:(NSInvocation *)anInvocation forward the method signature that is unable to handle the message to a nil object without causing a crash. In addition, common crashes such as NSArray value out of bounds and NSDictionary passing a nil object can be solved by using Method Swizzle in Runtime to hook the native method, as follows:
This solution can avoid errors such as array value out of bounds, dictionary passing null values, removeObjectAtIndex, etc. The following crash can be avoided:
2.2 Monitoring System Currently, most apps integrate third-party statistics libraries, such as Tencent's Bugly, U-App from Umeng, etc. Here we introduce how to build your own performance monitoring library. You can use PLCrashReporter or KSCrash library to parse the crash log and symbolize it, then upload it to the backend, collect and count it yourself. By the way, we used PLCrashReporter and Laravel in the backend, which made it very convenient to develop a simple crash and various performance parameter collection system, so if you want to build it yourself, you can consider this combination.
How to listen to these events? Check the source code, the simplified logic of the core method CFRunLoopRun is as follows:
We can see that if the waiting time in kCFRunLoopBeforeSources and kCFRunLoopBeforeWaiting is too long, it can be judged as a jam. What is specifically considered a jam? We all know that FPS is about 60 frames per second***, FPS is Frames Per Second. Strictly speaking, 60 frames per second is considered smooth, that is, one frame takes 1s/60 = 16.6ms. Considering the influence of some other events, several consecutive 50ms or a single time consumption is too long can be judged as a jam. After judging it as a jam, we can use PLCrashReporter or KSCrash to generate log records, which can be stored locally We can use CFRunLoopObserverRef to obtain the changes of NSRunLoop status value in real time. The following is an example:
Crash gracefully and upload crash logs By using NSSetUncaughtExceptionHandler to register your own exception handling callback, you can make the program appear calmer when a crash occurs, instead of directly crashing. You can pop up your own crash exception interface, which you can refer to Bilibili's interface. For example, if you encounter a high-energy reaction ahead, the program needs to be restarted, etc., so that users will not feel that the crash is abrupt. You can also manually maintain the Runloop after receiving the crash log. The following is a sample:
extend: The monitoring system is not limited to performance and crash rate, but can also extend statistical strategies to network request connectivity rate or some business levels to better control the quality of the App. 2.3 Performance Tuning & App Experience Optimization Earlier, we introduced how to effectively reduce crashes and handle crashes gracefully. Now let’s take a look at a few points to pay attention to when solving performance problems. 2.3.1 Advantages and Disadvantages of Lazy Loading Lazy loading is suitable for some pages that may not be loaded, such as pop-up boxes, empty data pages, etc. If used properly, it can avoid memory explosion. If used improperly, such as using lazy loading in a page that is bound to pop up, it may increase the page response time. Therefore, when using lazy loading, you must pay attention to the usage scenario to avoid side effects. 2.3.2 Avoid using repaint Overriding the drawRect or drawReact:inContext method will create a layer context by default. The memory required for the graphics context is layer width * layer height * 4 bytes. Each time the layer is redrawn, the memory needs to be erased and reallocated, which will incur huge performance overhead. The UIView class is actually an encapsulation of CALayer. There are many things about UI-level performance optimization. You can read the chapter about layer performance in iOS CoreAnimation Advanced Programming. 2.3.3 App experience optimization When it comes to App experience optimization, it is actually a metaphysics. You need to find a balance between performance and experience. Common bad experiences include:
These problems are just the details of the App, but starting from the details can make it more professional~ Let's focus on network request optimization: 2.3.3.1 Manually maintain DNS resolution Take www.manoboo.com as an example. When accessing through a domain name, the DNS resolution server will be searched first, and then it will be mapped to the IP of your own server. We can directly use the IP request interface to access network resources, which can avoid many problems, but there are pros and cons. You need to maintain the DNS mapping yourself. For example:
At this point, we can consider doing DNS resolution manually. To make it simple, we can replace the domain name in the URL when making a network request, or implement the corresponding method of the subclass of NSURLProtocol (URLProtocol in Swift) in Objective-C to replace the URL globally. However, there are some disadvantages:
2.3.3.2 Network request cache optimization Applicable scenarios: Some scenarios with low update frequency: such as personal center Regarding network request caching, the network requests from the App side are more about adding, deleting, modifying and querying to the backend. This aspect requires cooperation with the backend. Whether the resource changes, that is, whether the backend needs to re-retrieve or modify the data, at this time we need a value such as the timestamp Last-Modified or the identifier ETag to inform the server of its current resource tag. The commonly used strategies are: Take the timestamp Last-Modified as an example
Note: Quantification rather than guesswork is a principle in our development process. When we encounter performance problems, we can use instruments to measure various parameters in the actual operation process and find the problem (it is recommended to debug on a real machine instead of a simulator, as a real machine can better restore performance problems) The tools in instruments have their own uses. For example, you can use Leask to check for memory leaks during the app's operation, use TimeProfiler to check the app startup time or method time, or you can be lazy and use the difference between CACurrentMediaTime() to calculate the method time. Conclusion Due to space limitations, some points are also generalized. How to optimize a project in iOS is a very deep subject, and the knowledge points are very wide. I have only touched upon a part of it. Learning never ends. While completing work, we can also be a cool programmer, learn Haskell to experience the fun of functional programming thinking, or use LLDB to be a better debugger. ***, thank you very much for reading this article. If my article is helpful, you can give me a little red heart??, welcome to my website www.manoboo.com to give me some feedback, I will try my best to create better articles The articles cited in this article are as follows: CocoaChina - iOS real-time freeze monitoring iOS Core Animation: Advanced Techniques The open source libraries involved in this article are as follows: PLCrashReporter KSCrash MBNullSafe NullSafe library written by ManoBoo will further expand the functionality |
<<: Let's talk about APP push and analyze how each end collaborates to complete the push task
>>: Four advantages and five applications of machine learning in the financial field
This article’s 95-point growth plan is mainly div...
In the past, when food resources were scarce, it ...
Recently, the Ministry of Agriculture and Rural A...
Course Contents: Qihao Operation Practice Course....
[[149777]] People like to use a single chain of l...
The old-fashioned pedal sewing machine should be ...
Space elevators have been a frequently mentioned ...
"Dad's Laboratory" has been providi...
There are various celestial bodies in the univers...
Your browser does not support the video tag Autho...
I often joke with my friends: Young people, don’t...
Review expert: Qian Hang, aerospace science exper...
Written by: Zhu Hengheng Editor: Wang Haha Layout...