IOS performance optimization for page loading speed

IOS performance optimization for page load rates

preface

Trawling the Internet before a lot of information about the iOS performance optimization, I and my friends also took some time for your App to the App start-up rate, loading rate and frame rate of the page of the page is optimized, so the combination of theory and practice, our main tread pit in practice and need to be aware of things, I hope I can help you when you are preparing for App performance optimization. Today, I will focus on the optimization of the page loading rate of App.

purpose

In order to find out what really makes our App slow, we use Xcode or some third-party platforms to do data testing;

I. Definition of page loading rate

Page load Rate: For page load speed statistics, we test the time it takes a ViewController to get from the first line of ViewDidLoad to the last line of viewDidAppear.

Second, the target value of page loading rate

Goal: In order to understand the reason why the page loading speed of our App is relatively slow, we optimized the UI of the page and asynchronously loaded the data. When we hooked the data, the page loading speed was indeed reduced. However, the reduced value was only about 0.03s, which was obviously not enough to achieve the desired effect. Later, after writing some test demos and comparing blank pages with pages with UI creation, it seemed to have a great relationship with the push animation in the page loading process. The following experiment is mainly to verify this problem. For this problem, I selected a class of our project to test the cutscene and no animation when push enters this page. The following data are the test results:

Through the experiment, we can see that do not add animation, our page loading speed is no card, super fast, but if the cinematic sequences to open, single is animation time is around 0.5 s, and s is we want users to click on the jump of the page, aims at page 0.3 s [note: 0.3s is defined based on the 2-5-8 principle of performance optimization for your App. That is, when the user can get the response within 2 seconds, he will feel the response of the system is fast; when the user gets the response between 2-5 seconds, he will feel the response speed of the system is ok; when the user gets the response within 5-8 seconds, he will feel the response speed of the system is slow but acceptable; when the user can get the response within 5-8 seconds, he will feel the response speed of the system is slow but acceptable. When the user still can’t get a response after more than 8 seconds, he will feel that the system is terrible, or think that the system has lost its response, and choose to leave) 】 left and right, which is difficult to achieve if animation is added; However, by looking at the relevant information, we proved that we could remove the animation if there was a cutscene on the page, and instead add a cutscene to the user at a time that we could control, rather than wait for the animation to finish loading the page. This means that you can animate while the page is already loading, which greatly optimizes the page load time.

3. Data before optimization

4. Optimized data

5. How to collect data

  1. Create a class for UIViewController eg :UIViewController+Swizzle

  2. The following code

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

@interface UIViewController (Swizzle)
@property(nonatomic,assign) CFAbsoluteTime viewLoadStartTime;

@end

Copy the code
#import "UIViewController+Swizzle.h"
#import <objc/runtime.h>

static char *viewLoadStartTimeKey = "viewLoadStartTimeKey";
@implementation UIViewController (Swizzle)
-(void)setViewLoadStartTime:(CFAbsoluteTime)viewLoadStartTime{
objc_setAssociatedObject(self, &viewLoadStartTimeKey, @(viewLoadStartTime), OBJC_ASSOCIATION_COPY);

}
-(CFAbsoluteTime)viewLoadStartTime{
return [objc_getAssociatedObject(self, &viewLoadStartTimeKey) doubleValue];
}
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL origSel = @selector(viewDidAppear:);
SEL swizSel = @selector(swiz_viewDidAppear:);
[UIViewController swizzleMethods:[self class] originalSelector:origSel swizzledSelector:swizSel];

SEL vcWillAppearSel=@selector(viewWillAppear:);
SEL swizWillAppearSel=@selector(swiz_viewWillAppear:);
[UIViewController swizzleMethods:[self class] originalSelector:vcWillAppearSel swizzledSelector:swizWillAppearSel];

SEL vcDidLoadSel=@selector(viewDidLoad);
SEL swizDidLoadSel=@selector(swiz_viewDidLoad);
[UIViewController swizzleMethods:[self class] originalSelector:vcDidLoadSel swizzledSelector:swizDidLoadSel];

SEL vcDidDisappearSel=@selector(viewDidDisappear:);
SEL swizDidDisappearSel=@selector(swiz_viewDidDisappear:);
[UIViewController swizzleMethods:[self class] originalSelector:vcDidDisappearSel swizzledSelector:swizDidDisappearSel];

SEL vcWillDisappearSel=@selector(viewWillDisappear:);
SEL swizWillDisappearSel=@selector(swiz_viewWillDisappear:);
[UIViewController swizzleMethods:[self class] originalSelector:vcWillDisappearSel swizzledSelector:swizWillDisappearSel];
});
}

+ (void)swizzleMethods:(Class)class originalSelector:(SEL)origSel swizzledSelector:(SEL)swizSel
{
Method origMethod = class_getInstanceMethod(class, origSel);
Method swizMethod = class_getInstanceMethod(class, swizSel);

//class_addMethod will fail if original method already exists
BOOL didAddMethod = class_addMethod(class, origSel, method_getImplementation(swizMethod), method_getTypeEncoding(swizMethod));
if (didAddMethod) {
class_replaceMethod(class, swizSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
//origMethod and swizMethod already exist
method_exchangeImplementations(origMethod, swizMethod);
}
}

- (void)swiz_viewDidAppear:(BOOL)animated
{
[self swiz_viewDidAppear:animated];
if (self.viewLoadStartTime) {
CFAbsoluteTime linkTime = (CACurrentMediaTime() - self.viewLoadStartTime);

NGLog(@"% fs -------------------- SSSSSS %@: Speed: % fs",self.viewLoadStartTime, self.class,linkTime  );
self.viewLoadStartTime = 0;
}
}

-(void)swiz_viewWillAppear:(BOOL)animated
{
[self swiz_viewWillAppear:animated];
}

-(void)swiz_viewDidDisappear:(BOOL)animated
{
[self swiz_viewDidDisappear:animated];
}

-(void)swiz_viewWillDisappear:(BOOL)animated
{
[self swiz_viewWillDisappear:animated];
}
-(void)swiz_viewDidLoad
{
self.viewLoadStartTime =CACurrentMediaTime();
NSLog(@" %@swiz_viewDidLoad startTime:%f",self.class, self.viewLoadStartTime );
[self swiz_viewDidLoad];
}

@end
Copy the code

## How to optimize

  1. Method: Make full use of the time of push animation, so that when the page is entering, colleagues will carry out similar push animation, which can fully reduce the loading speed of the page (excluding the network request time, which is difficult to be controlled by us).

  2. Rewrite the push method as follows

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {

if (self.viewControllers.count > 0) {
viewController.hidesBottomBarWhenPushed = YES;
if(animated) { CATransition *animation = [CATransition animation]; Animation. Duration = 0.4 f; animation.timingFunction = [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromRight;
[self.navigationController.view.layer addAnimation:animation forKey:nil];
[self.view.layer addAnimation:animation forKey:nil];
[super pushViewController:viewController animated:NO];
return;
}
}
[super pushViewController:viewController animated:animated];
}

Copy the code
  1. From the console, we can see how fast the page is loading. The main methods are swiz_viewDidLoad and swiz_viewDidAppear

6. Results after optimization

7. Result analysis

We can see that our page’s viewDidAppear is called after the end of the cutscene, which lasts about 0.5 seconds. So our average page is about 0.8 seconds of the page, if we want to optimize better, we can see if there is a way to solve this problem, if we can replace the animation, so that the animation in the process, the page loading is also asynchronous, so that we can shorten the page loading time; Note: But this load does not apply to pages loaded with H5;

A simple demo, due to the content is not much, so the effect is not too obvious

Github.com/chenHuiMing…