iOS之優(yōu)化

1鞠评、盡可能的使用reuseIdentifier
盡可能的使用系統(tǒng)已經(jīng)實現(xiàn)的重用機制夏块。如UITableViewCell北专、UICollectionViewCell畦徘、UITableViewHeaderFooterView等毕籽;

為了性能最優(yōu)化抬闯,table view用 tableView:cellForRowAtIndexPath: 為rows分配cells的時候,它的數(shù)據(jù)應該重用自UITableViewCell关筒。 一個table view維持一個隊列的數(shù)據(jù)可重用的UITableViewCell對象溶握。不使用reuseIdentifier的話,每顯示一行table view就不得不設置全新的cell蒸播。這對性能的影響可是相當大的睡榆,尤其會使app的滾動體驗大打折扣。

2袍榆、盡量把view設置為完全不透明
opaque屬性盡可能設置為YES胀屿。
這個屬性給渲染系統(tǒng)提供了一個如何處理這個view的提示。如果設為YES包雀, 渲染系統(tǒng)就認為這個view是完全不透明的宿崭,這使得渲染系統(tǒng)優(yōu)化一些渲染過程和提高性能。如果設置為NO才写,渲染系統(tǒng)需要結合上層view的色值和透明度葡兑,更為復雜的計算當前view的顏色值等,復雜的計算和渲染必然導致性能的下降赞草,尤其是滾動視圖的情況讹堤。

3、避免過于龐大的XIB
首先厨疙,xib的類被初始化洲守,是作為nib文件被加載到內(nèi)存中的,尤其是當XIB有引用大量圖片或音頻資源的情況下轰异,大量文件被加載到內(nèi)存中必然導致性能的下降岖沛。所以,一是盡可能避免XIB的使用搭独,二是不可避免的情況下婴削,盡可能減小XIB文件的大小或者說復雜度

4、不要阻塞主線程
UIKit層的所有任務一定在主線程牙肝,包括UI渲染唉俗,觸摸點擊等事件響應等,長時間的耗時操作配椭,諸如網(wǎng)絡請求虫溜、本地數(shù)據(jù)庫操作等如果放在主線程,必然會導致UIKit層的響應變慢或者延遲股缸,會直接影響到用戶的感受衡楞,所以耗時操作可另外開辟線程執(zhí)行,如GCD和NSOperationQueue

5敦姻、圓角圖片

  • 直接設置imageV.layer.cornerRadius和imageV.layer.masksToBounds = YES必然會導致離屏渲染瘾境,大量使用圓角圖片的前提下歧杏,這種方法不可取
  • 使用CAShapeLayer和UIBezierPath設置圓角,在設置好image的imageView上繪制一層圓形遮罩迷守,此方法類似設置masksToBounds = YES犬绒,不可取
UIImageView * imageview = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 150, 150)];
imageview.center = self.view.center;
imageview.image = [UIImage imageNamed:@"meinv"];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageview.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageview.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
//設置大小
maskLayer.frame = imageview.bounds;
//設置圖形樣子
maskLayer.path = maskPath.CGPath;
imageview.layer.mask = maskLayer;
[self.view addSubview:imageview];
  • 使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角圖片,可取兑凿,沒有離屏渲染
UIImageView * imageview = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 150, 150)];
imageview.center = self.view.center;
imageview.image = [UIImage imageNamed:@"meinv"];
//開始對imageView進行畫圖
UIGraphicsBeginImageContextWithOptions(imageview.bounds.size, TRUE, 0);
//使用貝塞爾曲線畫出一個圓形圖
[[UIBezierPath bezierPathWithOvalInRect:imageview.bounds] addClip];
[imageview drawRect:imageview.bounds];
imageview.image = UIGraphicsGetImageFromCurrentImageContext();
//結束畫圖
UIGraphicsEndImageContext();
[self.view addSubview:imageview];

6凯力、重用和懶加載views
更多的view意味著更多的渲染,也就是更多的CPU和內(nèi)存消耗礼华,對于那種嵌套了很多view在UIScrollView里邊的app更是如此咐鹤;
這里我們用到的技巧就是模仿UITableView和UICollectionView的操作: 不要一次創(chuàng)建所有的subview,而是當需要時才創(chuàng)建卓嫂,當它們完成了使命慷暂,把他們放進一個可重用的隊列中聘殖。

7晨雳、正確使用緩存
原則:緩存所需要的,也就是那些不大可能改變但是需要經(jīng)常讀取的東西奸腺。諸如餐禁,遠端服務器的響應,圖片突照,甚至計算結果帮非,比如UITableView的行高。
為此讹蘑,你可以借助工具或者第三方末盔,避免不必要的多次請求和計算,如SDWebImage內(nèi)部實現(xiàn)了圖片的緩存座慰,UITableView-FDTemplateLayoutCell緩存UITableView的行高陨舱;

8、權衡渲染方法
對于簡單的視圖和動畫版仔,通常我們使用UIView就可以完成游盲,但是對于一些較為復雜的視圖和動畫,我們不得不動用Core Graphics層的繪圖和動畫機制蛮粮。這個時候益缎,我們就要根據(jù)情況,鑒于性能和效果兩個方面去考慮然想,找到更適合的處理方式

9莺奔、處理內(nèi)存警告
一旦系統(tǒng)內(nèi)存過低,iOS會通知所有運行中app变泄。在官方文檔中是這樣記述:
如果你的app收到了內(nèi)存警告令哟,它就需要盡可能釋放更多的內(nèi)存熙卡。最佳方式是移除對緩存,圖片object和其他一些可以重創(chuàng)建的objects的strong references励饵。
幸運的是驳癌,UIKit提供了幾種收集低內(nèi)存警告的方法:
1、在app delegate中使用applicationDidReceiveMemoryWarning: 的方法
2役听、在你的自定義UIViewController的子類(subclass)中覆蓋didReceiveMemoryWarning
3颓鲜、注冊并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
一旦收到這類通知,你就需要釋放任何不必要的內(nèi)存使用典予。
例如甜滨,UIViewController的默認行為是移除一些不可見的view, 它的一些子類則可以補充這個方法瘤袖,刪掉一些額外的數(shù)據(jù)結構衣摩。一個有圖片緩存的app可以移除不在屏幕上顯示的圖片。
這樣對內(nèi)存警報的處理是很必要的捂敌,若不重視艾扮,你的app就可能被系統(tǒng)殺掉。
然而占婉,當你一定要確認你所選擇的object是可以被重現(xiàn)創(chuàng)建的來釋放內(nèi)存泡嘴。一定要在開發(fā)中用模擬器中的內(nèi)存提醒模擬去測試一下。

10逆济、重用大開銷對象和重復使用的對象
對于一些初始化很慢酌予,而且又經(jīng)常使用的對象,最好設置成類的屬性或者封裝成單例(整個app只會創(chuàng)建一次)奖慌,比如NSDateFormatter和NSCalendar抛虫,百度地圖中常用的定位BMKLocationService對象
下面,使用延遲加載來實現(xiàn)重用

@property (nonatomic, strong)NSDateFormatter *dateFormat;
//在第一次使用的時候才會創(chuàng)建简僧,后來再使用就用第一次創(chuàng)建好的對象建椰,不會多次創(chuàng)建
-(NSDateFormatter *)dateFormat{
    if (!_dateFormat) {
        _dateFormat = [[NSDateFormatter alloc]init];
        _dateFormat.dateFormat = @"YYYY-MM-DD HH:mm:ss";
    }
    return _dateFormat    
}

11、盡量使用WebKit
UIWebView是基于移動版的Safari的涎劈,所以它的性能表現(xiàn)十分有限广凸。特別是在對幾乎每個Web應用都會使用的JavaScript,表現(xiàn)的尤為糟糕蛛枚。而iOS8引入的WebKit框架使得開發(fā)者可以在原生App中使用Nitro來提高網(wǎng)頁的性能和表現(xiàn)谅海,Nitro就是Safari的JavaScript引擎。WKWebView保證在滑動時保持60的幀率蹦浦,同時具有KVO扭吁,內(nèi)建手勢,以及在App和網(wǎng)頁之間的原生交流方式。

12侥袜、選擇正確的數(shù)據(jù)存儲選項
iOS的本地數(shù)據(jù)存儲方式有:

  • NSUserDefault
  • XML, JSON, 或者 plist
  • NSCoding歸檔
  • SQLite
  • Core Data
    首先蝌诡,NSUserDefault很好用,但只適用于小數(shù)據(jù)枫吧,類似簡易的字段值浦旱;
    XML和JSON這種結構化歸檔,還需要把數(shù)據(jù)讀到內(nèi)存中去解析九杂,NSCoding也需要歸檔和解檔配合解析數(shù)據(jù)颁湖,中間過程過于復雜,特別是大數(shù)據(jù)的情況就更不適合了例隆。

而SQLite和CoreData這種都能實現(xiàn)數(shù)據(jù)庫式的存儲甥捺,只要通過特定的語句就能實現(xiàn)數(shù)據(jù)的讀寫,唯一不同的是CoreData存儲過程中多了一層映射镀层,可以直接操作Object镰禾,而SQLite操作的是單個的原始數(shù)據(jù),而實際存儲后的結果都是DBMS

13唱逢、加速啟動時間
從點擊AppIcon啟動應用吴侦,到第一個畫面出現(xiàn),應用的啟動時間惶我,直接影響用戶對一款應用的判斷和使用體驗妈倔。關于啟動時間和如何優(yōu)化

簡而言之:t(App總啟動時間) = t1(main()之前的加載時間) + t2(main()之后的加載時間)博投。

  • 對于main()調(diào)用之前的耗時我們可以優(yōu)化的點有:
    1绸贡、減少不必要的framework,因為動態(tài)鏈接比較耗時
    2毅哗、check framework應當設為optional和required听怕,如果該framework在當前App支持的所有iOS系統(tǒng)版本都存在,那么就設為required虑绵,否則就設為optional尿瞭,因為optional會有些額外的檢查
    3、合并或者刪減一些OC類翅睛,關于清理項目中沒用到的類声搁,使用工具AppCode代碼檢查功能
    4、刪減一些無用的靜態(tài)變量
    5捕发、刪減沒有被調(diào)用到或者已經(jīng)廢棄的方法疏旨。方法見:
    http://stackoverflow.com/questions/35233564/how-to-find-unused-code-in-xcode-7 https://developer.Apple.com/library/ios/documentation/ToolsLanguages/Conceptual/Xcode_Overview/CheckingCodeCoverage.html
    6、將不必須在+load方法中做的事情延遲到+initialize中
    7扎酷、盡量不要用C++虛函數(shù)(創(chuàng)建虛函數(shù)表有開銷)

  • main()調(diào)用之后的加載時間
    在main()被調(diào)用之后檐涝,App的主要工作就是初始化必要的服務,顯示首頁內(nèi)容等。App通常在AppDelegate類中的- (BOOL)Application:(UIApplication )Application didFinishLaunchingWithOptions:(NSDictionary )launchOptions方法中創(chuàng)建首頁需要展示的view谁榜,然后在當前runloop的末尾幅聘,主動調(diào)用CA::Transaction::commit完成視圖的渲染。而視圖的渲染主要涉及三個階段:
    ** 準備階段 這里主要是圖片的解碼
    ** 布局階段 首頁所有UIView的- (void)layoutSubViews()運行
    ** 繪制階段 首頁所有UIView的- (void)drawRect:(CGRect)rect運行
    再加上啟動之后必要服務的啟動窃植、必要數(shù)據(jù)的創(chuàng)建和讀取帝蒿,這些就是我們可以嘗試優(yōu)化的地方
    因此,對于main()函數(shù)調(diào)用之后我們可以優(yōu)化的點有:
    1巷怜、不使用xib陵叽,直接視用代碼加載首頁視圖
    2、NSUserDefaults實際上是在Library文件夾下會生產(chǎn)一個plist文件丛版,如果文件太大的話一次能讀取到內(nèi)存中可能很耗時巩掺,這個影響需要評估,如果耗時很大的話需要拆分(需考慮老版本覆蓋安裝兼容問題)
    3页畦、每次用NSLog方式打印會隱式的創(chuàng)建一個Calendar胖替,因此需要刪減啟動時各業(yè)務方打的log,或者僅僅針對內(nèi)測版輸出log
    4豫缨、梳理應用啟動時發(fā)送的所有網(wǎng)絡請求独令,是否可以統(tǒng)一在異步線程請求

14、使用Autorelease Pool
NSAutoreleasePool負責釋放block中的autoreleased objects好芭。一般情況下它會自動被UIKit調(diào)用燃箭。但是有些狀況下你也需要手動去創(chuàng)建它。
當在項目中處理數(shù)據(jù)等需要很多臨時變量的時候舍败,你會發(fā)現(xiàn)內(nèi)存持續(xù)增長招狸,只有當這些臨時變量release的時候,內(nèi)存才有所緩解邻薯;我們知道每創(chuàng)建一個對象裙戏,他會被添加到距離最近的Autoreleasepool中,所以厕诡,我們可以自己創(chuàng)建AutoreleasePool累榜,使這些臨時變量可以盡早被釋放。

    //每次遍歷autorelease pool都會釋放里面的變量
    NSArray *urls = <# An array of file URLs #>;
    for(NSURL *url in urls) {
        @autoreleasepool {
            NSError *error;
            NSString *fileContents = [NSString stringWithContentsOfURL:url
                                             encoding:NSUTF8StringEncoding error:&error];
            /* Process the string, creating and autoreleasing more objects. */
        }
    }

15灵嫌、用正確的方式加載圖片
常見的從bundle中加載圖片的方式有兩種壹罚,一個是用imageNamed,二是用imageWithContentsOfFile寿羞,第一種比較常見一點猖凛。

既然有兩種類似的方法來實現(xiàn)相同的目的,那么他們之間的差別是什么呢稠曼?

imageNamed的優(yōu)點是當加載時會緩存圖片形病。imageNamed的文檔中這么說:
這個方法用一個指定的名字在系統(tǒng)緩存中查找并返回一個圖片對象如果它存在的話客年。如果緩存中沒有找到相應的圖片,這個方法從指定的文檔中加載然后緩存并返回這個對象漠吻。
相反的量瓜,imageWithContentsOfFile僅加載圖片。
下面的代碼說明了這兩種方法的用法:

UIImage *img = [UIImage imageNamed:@"myImage"];// caching
UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"];// no caching

那么途乃,對于占用內(nèi)存大且一次性使用的绍傲,就使用不會緩存的imageWithContentsOfFile,常用的小圖片或者icon就用會緩存的imageNamed耍共;

16烫饼、盡可能避免日期格式轉換
NSDateFormatter的創(chuàng)建和設置都是很耗時的操作,用日期字符串轉日期的情況也很常出現(xiàn)试读。提高效率的其中一個方法是重用NSDateFormatter對象杠纵,那如果需要不同樣式的NSDateFormatter呢?
還有一個方法钩骇,盡量使用Unix時間戳比藻,NSDate有直接從時間戳轉換為日期的方法

- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
    return  [NSDate dateWithTimeIntervalSince1970:timestamp];
 }

17、tableView的優(yōu)化系列
1倘屹、行高rowHeight的緩存UITableView+FDTemplateLayoutCell
2银亲、有圖片的cell復用時,加載圖片的方式做優(yōu)化纽匙,例如圓角處理务蝠,較大的圖片滑動過程中的加載方式 cell圖片加載優(yōu)化
3、Color Blend Layers(圖層渲染烛缔,避免復合圖層和圖層透明) + Color Hits Green and Misses Red(光柵化shouldRasterize = YES, 預先渲染成位圖并緩存,導致離屏渲染) + Color Misaligned Images(避免圖片縮放) + Color OffScreen-Rendered Yellow(離屏渲染馏段,圓角maskToBound = YES導致,合理處理圓角)
4力穗、參考文章 UIKit優(yōu)化

18毅弧、能用CAShapeLayer實現(xiàn)的就不要用drawRect重繪
原因分析: http://blog.csdn.net/sandyloo/article/details/51063799

  • 渲染快速。CAShapeLayer使用了硬件加速当窗,繪制同一圖形會比用Core Graphics快很多。
  • 高效使用內(nèi)存寸宵。一個CAShapeLayer不需要像普通CALayer一樣創(chuàng)建一個寄宿圖形崖面,所以無論有多大,都不會占用太多的內(nèi)存梯影。
  • 不會被圖層邊界剪裁掉巫员。
  • 不會出現(xiàn)像素化。

未完待續(xù)甲棍。简识。。。七扰。奢赂。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市颈走,隨后出現(xiàn)的幾起案子膳灶,更是在濱河造成了極大的恐慌,老刑警劉巖立由,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轧钓,死亡現(xiàn)場離奇詭異,居然都是意外死亡锐膜,警方通過查閱死者的電腦和手機毕箍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來道盏,“玉大人霉晕,你說我怎么就攤上這事±剔龋” “怎么了牺堰?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長颅围。 經(jīng)常有香客問我伟葫,道長,這世上最難降的妖魔是什么院促? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任筏养,我火速辦了婚禮,結果婚禮上常拓,老公的妹妹穿的比我還像新娘渐溶。我一直安慰自己,他們只是感情好弄抬,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布茎辐。 她就那樣靜靜地躺著,像睡著了一般掂恕。 火紅的嫁衣襯著肌膚如雪拖陆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天懊亡,我揣著相機與錄音依啰,去河邊找鬼。 笑死店枣,一個胖子當著我的面吹牛速警,可吹牛的內(nèi)容都是我干的叹誉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闷旧,長吁一口氣:“原來是場噩夢啊……” “哼长豁!你這毒婦竟也來了?” 一聲冷哼從身側響起鸠匀,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤蕉斜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后缀棍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宅此,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年爬范,在試婚紗的時候發(fā)現(xiàn)自己被綠了父腕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡青瀑,死狀恐怖璧亮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斥难,我是刑警寧澤枝嘶,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站哑诊,受9級特大地震影響群扶,放射性物質發(fā)生泄漏。R本人自食惡果不足惜镀裤,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一竞阐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧暑劝,春花似錦骆莹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至毁习,卻和暖如春智嚷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纺且。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稍浆,地道東北人载碌。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓猜嘱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嫁艇。 傳聞我的和親對象是個殘疾皇子朗伶,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,098評論 25 707
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件步咪、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,098評論 4 62
  • 2017年8月27號论皆,一切都很好,心情美麗
    鴿子hui0712閱讀 110評論 0 0
  • 落葉飄 飄…… 漂泊 微風漸起 托著葉的夢 飄得更遠 葉說 我想歸根 風兒說 我們相伴了多少個日夜 只想送你一程 ...
    張星_4968閱讀 117評論 0 0