頁面間跳轉(zhuǎn)的性能優(yōu)化(一)

頁面間跳轉(zhuǎn)的性能優(yōu)化(一)

來源:Delpan

鏈接:http://www.reibang.com/p/77847c0027c9

前言

現(xiàn)在App的頁面越來越復(fù)雜,頁面初始化的工作越來越多错邦,加載頁面所需的時(shí)間也隨之增長俗扇,如果頁面加載的時(shí)間過長粪狼,這將會(huì)影響App的流暢度及用戶體驗(yàn)视事,我們需要解決這一問題至耻。觀察過一些日常使用的App镣典,頁面間跳轉(zhuǎn)的性能問題總結(jié)為以下三種情形:

1).A頁面跳轉(zhuǎn)到B頁面,由于B頁面需要加載大量的數(shù)據(jù)运吓,所以導(dǎo)致頁面跳轉(zhuǎn)延遲渴邦。

2).A頁面跳轉(zhuǎn)到B頁面,由于B頁面需要加載大量UI元素拘哨,所以導(dǎo)致頁面跳轉(zhuǎn)延遲谋梭。

3).A頁面跳轉(zhuǎn)到B頁面,由于A或B頁面的GPU使用率過高倦青,所以導(dǎo)致面頁跳轉(zhuǎn)時(shí)出現(xiàn)過場動(dòng)畫不流暢瓮床,緩慢等。

情形一比較容易解決产镐,利用輔助線程加數(shù)據(jù)即可隘庄;由于圖層樹的更新(即UI頁面的更新)需要在主線程上完成,所以情形二的性能優(yōu)化讓很多開發(fā)人員頭痛癣亚;雖然網(wǎng)上有很多視圖性能優(yōu)化的技術(shù)文丑掺,但據(jù)了解,其實(shí)大部份團(tuán)隊(duì)都不會(huì)去做視圖的性能優(yōu)化述雾,情形三也是最普遍存在街州。本文將會(huì)講述這三種情形的性能優(yōu)化,但并不會(huì)講述頁面間跳轉(zhuǎn)的過渡動(dòng)畫玻孟,及頁面間跳轉(zhuǎn)的原理唆缴,這部份在網(wǎng)上已經(jīng)有大量技術(shù)文講述。關(guān)于情形三所涉及的像素混合黍翎,像素對(duì)齊面徽,離屏渲染等知識(shí)點(diǎn)將不進(jìn)行講述,本文會(huì)講述一種偷懶的方式來優(yōu)化情形三匣掸。

點(diǎn)擊下載Demo斗忌,或https://github.com/IOSDelpan/SmoothTransitionDemo质礼。

目錄

基礎(chǔ)知識(shí)

-渲染服務(wù)進(jìn)程

-UIView與CALayer

-圖層樹,呈現(xiàn)樹织阳,渲染樹

-UI更新過程

-RunLoop更新UI的工作

情形一

情形二

基礎(chǔ)知識(shí)

想在屏幕上顯示一個(gè)視圖,我們只需要簡單地實(shí)現(xiàn)以下代碼砰粹,并運(yùn)行Application到模擬器或真機(jī)即可唧躲。

-渲染服務(wù)進(jìn)程

雖然看到的效果跟Application的代碼是一一對(duì)應(yīng)的,但視圖繪制渲染的工作并不是由Application完成的碱璃,而是由一個(gè)名為渲染服務(wù)的進(jìn)程(BackBoard)來完成的弄痹,這個(gè)進(jìn)程的工作便是你在屏幕上看到的一切內(nèi)容。既然做實(shí)際繪制渲染工作的是渲染服務(wù)進(jìn)程嵌器,那么渲染服務(wù)進(jìn)程要進(jìn)行繪制渲染的依據(jù)是什么呢肛真?而Application跟渲染服務(wù)進(jìn)程又是怎么交互的呢?

-UIView與CALayer

為了方便往后的講述爽航,首先簡單講述一下UIView與CALayer的關(guān)系(不講述兩者的區(qū)別)蚓让。簡單來說,UIView就是CALayer的管理器讥珍,CALayer的主要工作是為屏幕的繪制渲染提供所需的數(shù)據(jù)源历极,也就是說,你在屏幕上看到的內(nèi)容衷佃,都是來源于CALayer趟卸。每一個(gè)UIView都有一個(gè)Backing Layer,UIView的UI屬性跟CALayer的屬性是一一對(duì)應(yīng)的氏义,設(shè)置UIView的UI屬性實(shí)際上是設(shè)置CALayer對(duì)應(yīng)的屬性锄列,即UIView的繪制渲染工作是由CALayer完成。UIView對(duì)象之間存在著一定的層級(jí)關(guān)系惯悠,那么所以UIView的Backing Layer也相應(yīng)的存在著一定的層級(jí)關(guān)系邻邮,這個(gè)層級(jí)關(guān)系叫做圖層樹(模型樹)。接下來的知識(shí)點(diǎn)直接用圖層來講述吮螺。

-圖層樹饶囚,呈現(xiàn)樹,渲染樹

使用Core Animation的Application(iOS默認(rèn)使用)鸠补,除了圖層樹萝风,還有呈現(xiàn)樹和渲染樹,每個(gè)圖層對(duì)象集合都扮演著不同的角色紫岩。圖層樹中的圖層對(duì)象負(fù)責(zé)存儲(chǔ)在屏幕上顯示的目標(biāo)值规惰,呈現(xiàn)樹中的圖層對(duì)象負(fù)責(zé)存儲(chǔ)在屏幕上顯示的瞬時(shí)值,而渲染樹的圖層對(duì)象是渲染服務(wù)進(jìn)程用來繪制渲染所使用的泉蝌。Application使用到的是圖層樹與呈現(xiàn)樹歇万,上圖中的代碼揩晴,使用的則是圖層樹中的圖層對(duì)象。既然渲染服務(wù)進(jìn)程使用的是渲染樹贪磺,那么圖層樹中的圖層對(duì)象所存儲(chǔ)的目標(biāo)值又是如何顯示在屏幕上呢硫兰?

-UI更新過程

在Application的主線程中設(shè)置圖層樹中的圖層對(duì)象時(shí),被設(shè)置的圖層對(duì)象會(huì)被標(biāo)記為待處理狀態(tài)(在輔助線程設(shè)置圖層對(duì)象寒锚,圖層對(duì)象不會(huì)被標(biāo)記)劫映,當(dāng)Application的主線程即將進(jìn)入休眠時(shí),Core Animation會(huì)打包圖層樹中待處理的圖層對(duì)象刹前,并通過IPC發(fā)送到渲染服務(wù)進(jìn)程泳赋,IPC是通過端口交互的,消息在兩個(gè)端口間傳遞喇喉,而渲染服務(wù)進(jìn)程的端口是不公開的(更多關(guān)于內(nèi)核方面的資料可以閱讀《OS X與iOS內(nèi)核編程》)祖今,當(dāng)打包的圖層發(fā)送到渲染服務(wù)進(jìn)程時(shí),這些圖層會(huì)被反序列化成渲染樹拣技,渲染服務(wù)進(jìn)程便可以開始繪制渲染的工作千诬。

-RunLoop更新UI的工作

Application的主線程為了保持存活狀態(tài),啟動(dòng)了運(yùn)行循環(huán)(RunLoop)过咬,RunLoop是一個(gè)事件處理循環(huán)大渤,使用RunLoop的目的是讓你的線程在有工作的時(shí)候忙于工作,而沒工作的時(shí)候處于休眠狀態(tài)掸绞。下圖為RunLoop調(diào)度的順序泵三。

從RunLoop調(diào)度的順序得知,當(dāng)沒有未處理事件時(shí)衔掸,線程就會(huì)進(jìn)入休眠狀態(tài)烫幕。在RunLoop中注冊了一個(gè)觀察者,這個(gè)觀察者用于監(jiān)聽線程即將進(jìn)入休眠的狀態(tài)敞映,當(dāng)線程即將進(jìn)入休眠時(shí)较曼,觀察者會(huì)執(zhí)行監(jiān)聽回調(diào)_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv(),這個(gè)函數(shù)實(shí)現(xiàn)了Core Animation打包圖層樹中待處理的圖層對(duì)象振愿,并通過IPC發(fā)送到渲染服務(wù)進(jìn)程的工作捷犹。本文不會(huì)提及深入的RunLoop原理,深入部份會(huì)在RunLoop篇講述冕末。

情形一

絕大多數(shù)的App頁面都是用來展示各式各樣的數(shù)據(jù)萍歉,如果跳轉(zhuǎn)頁面的同時(shí),在主線程加載大量的數(shù)據(jù)档桃,便會(huì)出現(xiàn)以下情況枪孩。

如Gif圖所示,屏幕卡頓了一會(huì)才出現(xiàn)頁面跳轉(zhuǎn)的過場動(dòng)畫,即出現(xiàn)了頁面跳轉(zhuǎn)延遲的情況蔑舞。從基礎(chǔ)知識(shí)的UI更新過程拒担,RunLoop更新UI的工作中得知,Application的UI更新在于主線程即將進(jìn)入休眠時(shí)攻询,RunLoop觀察者的回調(diào)函數(shù)_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()从撼,只要該函數(shù)執(zhí)行完,我們就可以在屏幕上看到UI更新的結(jié)果蜕窿。既然知道這是由于在主線程加載大量數(shù)據(jù)所致谋逻,那么我們來解決這一情形,首先需要知道是那個(gè)函數(shù)占用了CPU桐经,使用Instruments的Time Profiler測試一下。

從測試的結(jié)果可以看到浙滤,是setUpData這個(gè)方法占用了主線程阴挣,而setUpData方法是在viewDidLoad里被調(diào)用的,那么viewDidLoad又是在何時(shí)被調(diào)用的呢纺腊?

從主線程活動(dòng)的狀態(tài)以及執(zhí)行堆椗线郑可以看出,viewDidLoad是在_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()里被調(diào)用的揖膜,大致過程如下圖誓沸。

知道了問題函數(shù)和主線程的執(zhí)行堆棧,那么解決這一問題就變得很簡單壹粟。只需要把加載數(shù)據(jù)的setUpData方法放到輔助線程中執(zhí)行并返回結(jié)果到主線程顯示即可拜隧。

當(dāng)我們使用多線程去加載數(shù)據(jù)時(shí),由于主線程沒有被阻塞趁仙,所以沒有出現(xiàn)頁面跳轉(zhuǎn)延遲的情況洪添,具體代碼請(qǐng)看Demo。

情形二

在頁面跳轉(zhuǎn)時(shí)雀费,除了加載數(shù)據(jù)干奢,還需要加載UI元素,而加載UI元素的工作一般會(huì)在viewDidLoad中完成盏袄,如果需要加載的UI元素過多忿峻,同樣會(huì)出現(xiàn)頁面跳轉(zhuǎn)延遲的情況。

如Gif圖所示辕羽,出現(xiàn)了頁面跳轉(zhuǎn)延遲的情況逛尚,這是由于在viewDidLoad中生成大量的UI元素所致。在情形一中逛漫,我們用輔助線程加載數(shù)據(jù)解決了頁面跳轉(zhuǎn)延遲的情況黑低,那么我們可以以同樣的方式來加載UI元素。

雖然我們可以把生成UI元素的工作放到輔助線程中完成,且看到的效果相同克握,但這種處理方式的效率非常低蕾管,這種方式生成大量UI元素所需要的時(shí)間比直接在主線程中生成要多數(shù)倍,增加加載頁面所需要的時(shí)間菩暗,這顯然不是我們想要的結(jié)果掰曾,我們想要的是既可以在主線程生成UI,又可以不出現(xiàn)頁面跳轉(zhuǎn)延遲的情況停团。

我們知道當(dāng)Application的主線程即將進(jìn)入休眠時(shí)旷坦,Core Animation會(huì)打包圖層樹中待處理的圖層對(duì)象,除了打包圖層對(duì)象佑稠,Core Animation還會(huì)打包基礎(chǔ)動(dòng)畫對(duì)象秒梅,一并發(fā)送到渲染服務(wù)進(jìn)程,渲染服務(wù)進(jìn)程接收到圖層對(duì)象和動(dòng)畫對(duì)象后舌胶,會(huì)根據(jù)動(dòng)畫對(duì)象來不斷計(jì)算和繪制圖層對(duì)象捆蜀,形成屏幕上看到的動(dòng)畫效果,所以動(dòng)畫對(duì)象能否及時(shí)發(fā)送到渲染服務(wù)進(jìn)程就顯得非常重要幔嫂,這關(guān)系到你App的用戶體驗(yàn)辆它。頁面跳轉(zhuǎn)時(shí)的過場動(dòng)畫的打包工作,跟viewDidLoad是在同一次RunLoop中履恩,所以viewDidLoad的執(zhí)行時(shí)間就顯得很關(guān)鍵锰茉。除了viewDidLoad以外,在UIViewController的生命周期里還有另外幾個(gè)方法切心,我們來看一下這幾個(gè)方法的被調(diào)度的情況飒筑。

從打印信息中得知,viewWillAppear昙衅,viewWillLayoutSubviews扬霜,viewDidLayoutSubviews是緊跟viewDidLoad之后執(zhí)行的,所以這幾個(gè)方法的執(zhí)行時(shí)間同樣很重要而涉,但我們發(fā)現(xiàn)viewDidAppear方法并沒有被調(diào)度著瓶,即viewDidAppear跟前面幾個(gè)方法并在不同一次RunLoop中,既然如此啼县,我們可以便使用viewDidAppear來解決頁面跳轉(zhuǎn)延遲的情況材原。

Gif圖顯示的效果和根據(jù)基礎(chǔ)知識(shí)猜想的結(jié)果一樣,解決了頁面跳轉(zhuǎn)延遲的情況季眷,那么viewDidAppear何時(shí)被調(diào)用余蟹?

從主線程的執(zhí)行堆棧可得知子刮,viewDidAppear是在過場動(dòng)畫結(jié)束后被調(diào)用的威酒,而過場動(dòng)畫的持續(xù)時(shí)間是0.35秒窑睁。

我們來算一下整個(gè)過程所需要的時(shí)間,假設(shè)生成頁面需要0.5秒葵孤,那么優(yōu)化前后所需要的時(shí)間都是0.85秒(經(jīng)測試担钮,其實(shí)時(shí)間有減少,只是少到可以忽略尤仍,時(shí)間減少的部份應(yīng)該是GPU計(jì)算量的問題)箫津,雖然問題解決了,但效果并不理想宰啦,因?yàn)橥瓿烧麄€(gè)過程所需要的時(shí)間并沒有減少苏遥,所以我們需要進(jìn)一步優(yōu)化。嘗試過很多種方式赡模,但似乎沒有什么方式可以很好地減少生成UI元素所需要的時(shí)間田炭,那么我們只能把優(yōu)化的方向放在過場動(dòng)畫的持續(xù)時(shí)間上了。

從Gif圖顯示的效果可以看到漓柑,完成整個(gè)過程所需要的時(shí)間明顯減少了诫肠,實(shí)現(xiàn)原理請(qǐng)看下圖。

如圖所示欺缘,把生成UI元素的任務(wù)從本次RunLoop中抽出,提交到下一次的RunLoop當(dāng)中挤安,因?yàn)楸敬蜶unLoop沒有被阻塞谚殊,所以能及時(shí)把圖層對(duì)象和動(dòng)畫對(duì)象發(fā)送到渲染服務(wù)進(jìn)程,渲染服務(wù)進(jìn)程便開始進(jìn)行過場動(dòng)畫的繪制與渲染蛤铜,與此同時(shí)嫩絮,Application的主線程RunLoop進(jìn)入下一次Loop,開始執(zhí)行生成UI元素的任務(wù)围肥,即剿干,可以理解為渲染服務(wù)進(jìn)程繪制渲染過場動(dòng)畫,和Application生成UI元素的任務(wù)同時(shí)進(jìn)行穆刻,這樣我們便把動(dòng)畫的時(shí)間也利用上置尔,從而大大減小了整個(gè)過程所需的時(shí)間。

在Demo中氢伟,是使用GCD的方式來實(shí)現(xiàn)榜轿,也可以使用performSelector: withObject: afterDelay:方法來實(shí)現(xiàn)同樣的效果,但不建議朵锣,因?yàn)檫@樣會(huì)增加主線程RunLoop的執(zhí)行時(shí)間谬盐。

我們還可以把這個(gè)耗時(shí)的任務(wù)分解成若干個(gè)小的任務(wù)來實(shí)現(xiàn)。

如Gif圖所示诚些,沒有出現(xiàn)頁面跳轉(zhuǎn)延遲的情況飞傀。使用定器時(shí)把任務(wù)分解,可以得到同樣的結(jié)果,若是加上一些動(dòng)畫砸烦,效果會(huì)更棒弃鸦。在Demo中,用到的定時(shí)器是CADisplayLink外冀,用NSTimer可以達(dá)得到樣的效果寡键,關(guān)于CADisplayLink,建議能不用就不用雪隧,因?yàn)樗鼤?huì)使目標(biāo)線程長期處于活躍狀態(tài)西轩。

情形三將會(huì)在頁面間跳轉(zhuǎn)的性能優(yōu)化(二)中講述。如果文中有講錯(cuò)的地方脑沿,還望指出藕畔。

Tips:雖然黑科技很強(qiáng)大,但也很危險(xiǎn)庄拇,在你沒有足夠了解它的情況下注服,不能輕易去使用,更不能濫用措近。本文的講述旨在如何利用基礎(chǔ)知識(shí)來解決日常開發(fā)中遇到的問題溶弟,并不是硬式化地講解使用方式。

閱讀 281712 投訴

精選留言

寫留言

5

wh

放在 view did appear 每次調(diào)用那個(gè)頁面都會(huì)執(zhí)行一次吧 比如 返回這個(gè)頁面 也會(huì)調(diào)用一次

2天前

3

DENG

這個(gè)好瞭郑,mark

3天前

3

003

漲知識(shí)

3天前

以上留言由公眾號(hào)篩選后顯示

了解留言功能詳情

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辜御,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屈张,更是在濱河造成了極大的恐慌擒权,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阁谆,死亡現(xiàn)場離奇詭異碳抄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)场绿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門剖效,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人裳凸,你說我怎么就攤上這事贱鄙。” “怎么了姨谷?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵逗宁,是天一觀的道長。 經(jīng)常有香客問我梦湘,道長瞎颗,這世上最難降的妖魔是什么件甥? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮哼拔,結(jié)果婚禮上引有,老公的妹妹穿的比我還像新娘。我一直安慰自己倦逐,他們只是感情好譬正,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著檬姥,像睡著了一般曾我。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上健民,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天抒巢,我揣著相機(jī)與錄音,去河邊找鬼秉犹。 笑死蛉谜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崇堵。 我是一名探鬼主播型诚,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸳劳!你這毒婦竟也來了俺驶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤棍辕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后还绘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楚昭,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年拍顷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抚太。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昔案,死狀恐怖尿贫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踏揣,我是刑警寧澤庆亡,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站捞稿,受9級(jí)特大地震影響又谋,放射性物質(zhì)發(fā)生泄漏拼缝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一彰亥、第九天 我趴在偏房一處隱蔽的房頂上張望咧七。 院中可真熱鬧,春花似錦任斋、人聲如沸继阻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘟檩。三九已至,卻和暖如春锦积,著一層夾襖步出監(jiān)牢的瞬間芒帕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工丰介, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留背蟆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓哮幢,卻偏偏與公主長得像带膀,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子橙垢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 現(xiàn)在App的頁面越來越復(fù)雜垛叨,頁面初始化的工作越來越多,加載頁面所需的時(shí)間也隨之增長柜某,如果頁面加載的時(shí)間...
    Delpan閱讀 22,578評(píng)論 92 464
  • 續(xù)言 在頁面間跳轉(zhuǎn)的性能優(yōu)化(一)中介紹了一些基礎(chǔ)知識(shí)嗽元,講述了情形一與情形二的優(yōu)化方式及原理,但有許多人對(duì)情...
    Delpan閱讀 8,055評(píng)論 32 95
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,499評(píng)論 25 707
  • 寒降南山喂击,霜滿前庭剂癌。東風(fēng)惡、尤勝刀兵翰绊。 三春桃李佩谷,一夜霜清。見天殘?jiān)萍嗍龋藲堄靶程矗瑯錃埿巍?匹年窮歲,長情篤信裁奇。笑書生...
    十萬字的夢想閱讀 345評(píng)論 2 6
  • 1桐猬、復(fù)制字符串到剪切板 2、打電話 創(chuàng)建一個(gè)成員變量UIWebView來加載URL刽肠,撥完后能自動(dòng)回到原應(yīng)用 3课幕、發(fā)...
    univer2012閱讀 175評(píng)論 0 0