iOS性能優(yōu)化教程之頁面加載速率詳解

前言

成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、新市網(wǎng)絡(luò)推廣、成都微信小程序、新市網(wǎng)絡(luò)營(yíng)銷、新市企業(yè)策劃、新市品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供新市建站搭建服務(wù),24小時(shí)服務(wù)熱線:13518219792,官方網(wǎng)址:muchs.cn

我認(rèn)為在編碼過程中時(shí)刻注意性能影響是有必要的,但凡事都有個(gè)度,不能為了性能耽誤了開發(fā)進(jìn)度。在時(shí)間緊急的情況下我們往往采用“quick and dirty”的方案來快速出成果,后面再迭代優(yōu)化,即所謂的敏捷開發(fā)。與之相對(duì)應(yīng)的是傳統(tǒng)軟件開發(fā)中的瀑布流開發(fā)流程。

卡頓產(chǎn)生的原因

iOS性能優(yōu)化教程之頁面加載速率詳解

在 iOS 系統(tǒng)中,圖像內(nèi)容展示到屏幕的過程需要 CPU 和 GPU 共同參與。CPU 負(fù)責(zé)計(jì)算顯示內(nèi)容,比如視圖的創(chuàng)建、布局計(jì)算、圖片解碼、文本繪制等。隨后 CPU 會(huì)將計(jì)算好的內(nèi)容提交到 GPU 去,由 GPU 進(jìn)行變換、合成、渲染。之后 GPU 會(huì)把渲染結(jié)果提交到幀緩沖區(qū)去,等待下一次 VSync 信號(hào)到來時(shí)顯示到屏幕上。由于垂直同步的機(jī)制,如果在一個(gè) VSync 時(shí)間內(nèi),CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會(huì)被丟棄,等待下一次機(jī)會(huì)再顯示,而這時(shí)顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因。

因此,我們需要平衡 CPU 和 GPU 的負(fù)荷避免一方超負(fù)荷運(yùn)算。為了做到這一點(diǎn),我們首先得了解 CPU 和 GPU 各自負(fù)責(zé)哪些內(nèi)容。

iOS性能優(yōu)化教程之頁面加載速率詳解

上面的圖展示了 iOS 系統(tǒng)下各個(gè)模塊所處的位置,下面話不多說了,來一起看看本文的正文。

之前搜羅了網(wǎng)上很多關(guān)于iOS性能優(yōu)化方面的資料 ,本人和我的小伙伴們也用了一些時(shí)間針對(duì)自己的App進(jìn)行了App的啟動(dòng)速率、頁面的加載速率和 頁面的幀率方面進(jìn)行了優(yōu)化,所以結(jié)合了理論和實(shí)踐,把我們?cè)趯?shí)踐中主要踩過的坑和需要注意的東西 ,總結(jié)了一下,希望可以幫到正在準(zhǔn)備進(jìn)行App的性能優(yōu)化的你。今天主要講一下App的頁面加載速率的優(yōu)化。

##目的

為了找到真正使我們的App緩慢的原因,我們使用Xcode或者一些第三方平臺(tái),進(jìn)行數(shù)據(jù)測(cè)試;

一、頁面加載速率的定義

頁面加載速率:關(guān)于頁面的加載速度的統(tǒng)計(jì),我們是測(cè)試一個(gè)viewcontroller從viewdidload的第一行到viewdidappear的最后一行所用的時(shí)間。

二、頁面加載速率的目標(biāo)值

目標(biāo):頁面加載速率最好完美的時(shí)間在0.3s左右

為了弄明白,到底是什么原因讓我們的App,頁面加載速度相對(duì)來說比較慢,我們對(duì)頁面的UI進(jìn)行優(yōu)化,數(shù)據(jù)也進(jìn)行了異步加載,我們hook數(shù)據(jù)一看,頁面的加載速度果然有所減少,但是減少的值大概只有0.03s,很明顯這個(gè)值不足以達(dá)到我們想要的效果,后來,通過寫了一些測(cè)試demo,針對(duì)空白頁面和有UI創(chuàng)建的頁面進(jìn)行各種對(duì)比后,似乎和我們頁面加載過程中的push動(dòng)畫有很大的關(guān)系;下面所做的實(shí)驗(yàn)主要是為了驗(yàn)證這個(gè)問題,針對(duì)這個(gè)問題,我選取了我們工程的一個(gè)類,對(duì)有push進(jìn)入到這個(gè)頁面有過場(chǎng)動(dòng)畫和沒有動(dòng)畫進(jìn)行測(cè)試,以下數(shù)據(jù)是測(cè)試結(jié)果:

iOS性能優(yōu)化教程之頁面加載速率詳解

通過這個(gè)實(shí)驗(yàn),我們可以看出,不加動(dòng)畫的話,我們的頁面加載的速度可以說是沒有任何的卡頓,超級(jí)迅速,但是如果把過場(chǎng)動(dòng)畫給打開,單是動(dòng)畫的時(shí)間就是在0.5s左右,而s我們是希望用戶在點(diǎn)擊跳轉(zhuǎn)頁面的時(shí)候,目標(biāo)是頁面在0.3s左右呈現(xiàn),這如果加動(dòng)畫,這個(gè)目標(biāo)很難達(dá)到;不過通過查找相關(guān)資料,我們證實(shí)了我們可以把如果有過場(chǎng)動(dòng)畫的頁面,去掉動(dòng)畫,而是通過我們自己去給用戶添加一個(gè)過場(chǎng)動(dòng)畫,而這個(gè)時(shí)間是可以受到我們自己的控制,而不是傻傻的等動(dòng)畫結(jié)束后再加載頁面內(nèi)容。的這就是說,可以一邊動(dòng)畫的時(shí)候,一邊已經(jīng)開始加載頁面相關(guān)東西了,這樣可以大大的優(yōu)化頁面加載時(shí)間。

三、優(yōu)化前數(shù)據(jù)

iOS性能優(yōu)化教程之頁面加載速率詳解

四、 優(yōu)化后的數(shù)據(jù)

iOS性能優(yōu)化教程之頁面加載速率詳解

到這里 ,你一定想問 :我該如何hook數(shù)據(jù)的???

五、如何進(jìn)行數(shù)據(jù)的收集

給UIViewController 創(chuàng)建一個(gè)分類 eg :UIViewController+Swizzle

代碼如下

#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

##如何進(jìn)行優(yōu)化

方法:充分利用push 動(dòng)畫的時(shí)間 ,使頁面在進(jìn)入的時(shí)候,同事進(jìn)行類似push 動(dòng)畫,這樣可以充分減少頁面的加載速度(不包括網(wǎng)絡(luò)請(qǐng)求時(shí)間,網(wǎng)絡(luò)的請(qǐng)求的時(shí)間我們這邊不好控制)。

具體實(shí)現(xiàn)代碼如下

重寫 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];
}

通過控制臺(tái) ,我們就可以看到頁面的加載的速度了,主要的方法是swiz_viewDidLoad  和swiz_viewDidAppear

六、優(yōu)化后的結(jié)果

iOS性能優(yōu)化教程之頁面加載速率詳解

七、結(jié)果分析

我們可以看出,我們的頁面的viewDidAppear是在過場(chǎng)動(dòng)畫結(jié)束后被調(diào)用的,而過場(chǎng)動(dòng)畫的持續(xù)時(shí)間是0.5秒左右。所以我們的頁面平均在0.8秒左右的頁面,如果要優(yōu)化得更好,我們可以看有沒有方法解決這個(gè)問題,如果能替換掉動(dòng)畫,讓動(dòng)畫在進(jìn)行的過程中 ,頁面的加載也在異步的進(jìn)行中,這樣 我們就可以縮短頁面的加載時(shí)間了;注:但這個(gè)加載對(duì)加載h6的頁面不適用;

總結(jié):

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。

網(wǎng)站題目:iOS性能優(yōu)化教程之頁面加載速率詳解
文章來源:http://muchs.cn/article14/ijcide.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、ChatGPT網(wǎng)站制作、網(wǎng)站內(nèi)鏈、商城網(wǎng)站軟件開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)