iOS性能優化之頁面加載速率

iOS性能優化之頁面加載速度git

iOS性能優化之頁面加載速率github

前言性能優化

以前蒐羅了網上不少關於iOS性能優化方面的資料 ,本人和個人小夥伴們也用了一些時間針對本身的App進行了App的啓動速率、頁面的加載速率和 頁面的幀率方面進行了優化,因此結合了理論和實踐,把咱們在實踐中主要踩過的坑和須要注意的東西 ,總結了一下,但願能夠幫到正在準備進行App的性能優化的你。今天主要講一下App的頁面加載速率的優化。網絡

目的app

爲了找到真正使咱們的App緩慢的緣由,咱們使用Xcode或者一些第三方平臺,進行數據測試;異步

1、頁面加載速率的定義ide

頁面加載速率:關於頁面的加載速度的統計,咱們是測試一個viewcontroller從viewdidload的第一行到viewdidappear的最後一行所用的時間。性能

2、頁面加載速率的目標值測試

目標:頁面加載速率最好完美的時間在0.3s左右優化

爲了弄明白,究竟是什麼緣由讓咱們的App,頁面加載速度相對來講比較慢,咱們對頁面的UI進行優化,數據也進行了異步加載,咱們hook數據一看,頁面的加載速度果真有所減小,可是減小的值大概只有0.03s,很明顯這個值不足以達到咱們想要的效果,後來,經過寫了一些測試demo,針對空白頁面和有UI建立的頁面進行各類對比後,彷佛和咱們頁面加載過程當中的push動畫有很大的關係;下面所作的實驗主要是爲了驗證這個問題,針對這個問題,我選取了咱們工程的一個類,對有push進入到這個頁面有過場動畫和沒有動畫進行測試,如下數據是測試結果:

經過這個實驗,咱們能夠看出,不加動畫的話,咱們的頁面加載的速度能夠說是沒有任何的卡頓,超級迅速,可是若是把過場動畫給打開,單是動畫的時間就是在0.5s左右,而s咱們是但願用戶在點擊跳轉頁面的時候,目標是頁面在0.3s【注:0.3s是根據本身App的狀況 ,基於性能優化的2-5-8原則來定義的。(2-5-8原則:就是當用戶可以在2秒之內獲得響應時,會感受系統的響應很快;當用戶在2-5秒之間獲得響應時,會感受系統的響應速度還能夠;當用戶在5-8秒之內獲得響應時,會感受系統的響應速度很慢,可是還能夠接受;而當用戶在超過8秒後仍然沒法獲得響應時,會感受系統糟透了,或者認爲系統已經失去響應,而選擇離開)】左右呈現,這若是加動畫,這個目標很難達到;不過經過查找相關資料,咱們證明了咱們能夠把若是有過場動畫的頁面,去掉動畫,而是經過咱們本身去給用戶添加一個過場動畫,而這個時間是能夠受到咱們本身的控制,而不是傻傻的等動畫結束後再加載頁面內容。的這就是說,能夠一邊動畫的時候,一邊已經開始加載頁面相關東西了,這樣能夠大大的優化頁面加載時間。

3、優化前數據

4、 優化後的數據

到這裏 ,你必定想問 :我該如何hook數據的???

5、如何進行數據的收集

  1. 給UIViewController 建立一個分類 eg :UIViewController+Swizzle

  2. 代碼以下

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

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

    @end

    #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(@" %f s--------------------ssssss %@:速度: %f s",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

如何進行優化

  1. 方法:充分利用push 動畫的時間 ,使頁面在進入的時候,同事進行相似push 動畫,這樣能夠充分減小頁面的加載速度(不包括網絡請求時間,網絡的請求的時間咱們這邊很差控制)。

  2. 具體實現代碼以下 重寫 push方法

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

    if (self.viewControllers.count > 0) { viewController.hidesBottomBarWhenPushed = YES; if (animated) {

    CATransition *animation = [CATransition animation]; animation.duration = 0.4f; animation.timingFunction = [CAMediaTimingFunction functionWithName: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]; }

  3. 經過控制檯 ,咱們就能夠看到頁面的加載的速度了,主要的方法是swiz_viewDidLoad 和swiz_viewDidAppear

6、優化後的結果

7、結果分析

咱們能夠看出,咱們的頁面的viewDidAppear是在過場動畫結束後被調用的,而過場動畫的持續時間是0.5秒左右。因此咱們的頁面平均在0.8秒左右的頁面,若是要優化得更好,咱們能夠看有沒有方法解決這個問題,若是能替換掉動畫,讓動畫在進行的過程當中 ,頁面的加載也在異步的進行中,這樣 咱們就能夠縮短頁面的加載時間了;注:但這個加載對加載h5的頁面不適用;

一個簡單的demo ,因爲內容很少 ,因此效果不是太明顯

github地址:

github.com/chenHuiMing…

相關文章
相關標籤/搜索