iOS網(wǎng)絡(luò)優(yōu)化
1 優(yōu)化項目
- DNS
客戶端維護DNS映射表
1)定時向服務(wù)端獲取跟新
2)上報無效ip
3)保留替補映射表和默認DNS - 數(shù)據(jù)壓縮
- 請求合并
- 請求的安全性TLS
- 合理的并發(fā)數(shù)
并發(fā)數(shù)太少關(guān)鍵請求可能被阻塞,并發(fā)數(shù)太多HTTP隊首阻塞、帶寬、服務(wù)端壓力 - 可靠性保障
1)關(guān)鍵核心的業(yè)務(wù)數(shù)據(jù) ----------- 持久化 重發(fā)
2)重要內(nèi)容 --------------- 重發(fā)
3)一般性內(nèi)容 ------------- 一次發(fā)送 - 多通道
TCP,UDP,HTTP,WebSocket - 網(wǎng)絡(luò)環(huán)境監(jiān)控
重發(fā),交互提示 - 請求成功率監(jiān)控
上報成功率低的請求,及其網(wǎng)絡(luò)狀況、請求參數(shù)等數(shù)據(jù)。用于分析做深度優(yōu)化。
2 美團點評移動網(wǎng)絡(luò)優(yōu)化記錄
1)端到端監(jiān)控平臺,從用戶角度觀察網(wǎng)絡(luò)體驗,區(qū)別于后臺服務(wù)監(jiān)控。
http://mrpeak.cn/blog/ios-network/
http://www.mrpeak.cn/ios/2016/01/22/dnsmapping
https://tech.meituan.com/2017/03/17/shark-sdk.html
iOS UI優(yōu)化
- UIView
- Drawing and animation (Core Graphics, OpenGL ES, or UIKit)
- Event handling (gesture recognizers or by handling touch events directly)
- Layout and subview management
- The View Drawing Cycle
1)UIView 使用on-demand drawing model展示contents
view appear > draw content > 系統(tǒng)獲取content快照 > 如果view content不改變則重用快照顯示 > 否則通知系統(tǒng)view改變重復上述過程
2)view content改變之后不會立即重繪,需要調(diào)用setNeedsDisplayorsetNeedsDisplayInRect:告訴系統(tǒng)view content改變了,要在當前runloop結(jié)束之時到繪制操作初始化之前重繪(The system waits until the end of the current run loop before initiating any drawing operations)。在這期間可以同時
- invalidate multiple views,
- add or remove views,
- hide views,
- resize views,
- reposition views
注意:改變一個view的幾何特性不會自動通知系統(tǒng)重繪,content mode決定著如何改變view的幾何。大多數(shù)情況下會使用已經(jīng)存在的快照進行伸縮,位移。content mode的作用是控制view是否重用content以及如何重用。
補充:UI重繪時機是由runloop保證的,如果沒有runloop就無法確定UI何時回重繪,參考下面兩段代碼
// view1和view2都會在當前的runloop結(jié)束前跟新color
- (IBAction)changeColor:(id)sender {
__block NSRunLoop *loop;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
loop = [NSRunLoop currentRunLoop];
[loop performBlock:^{
self.view1.backgroundColor = [UIColor redColor];
}];
[loop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[loop run];
});
self.view2.backgroundColor = [UIColor redColor];
}
// view1會在當前的runloop結(jié)束前更新color;view2的更新時機不確定通常會延遲更新。
- (IBAction)changeColor:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.view1.backgroundColor = [UIColor redColor];
});
self.view2.backgroundColor = [UIColor redColor];
}
3)渲染view content時,真是的繪制過程取決于view及其設(shè)置:
- 系統(tǒng)view通過暴露出的借口設(shè)置外觀
- 自定義view通常復寫
drawRect:方法來繪制content - 也可以直接在layer上繪制
4)視圖緩存機制
在當前runloop視圖content改變后會被緩存,當前runloop結(jié)束后下一次循環(huán)系統(tǒng)view會自動調(diào)用drawRect方法進行重繪,如果是custom view需要調(diào)用setNeedsDisplay通知系統(tǒng)調(diào)用drawRect重繪。
3 如何高效實用view - content mode
- opaque
- 滾動時少繪制
4
1)iOS原生圖像系統(tǒng)主要有三種
- UIKit, 提供高層級的繪制功能
- Core Graphics, 提供低級繪制功能
- Core Animation. 提供變換、動畫和view合成功能
2)把內(nèi)容繪制到屏幕上的幾種方式
- Using standard (built-in) views.
- Using Core Animation layers.
- Using OpenGL ES in a GLKit view or a custom view.
- Using web content.
3)iOS提供兩種方案來創(chuàng)建高質(zhì)量的圖像
- OpenGL
- native rendering
a) Quartz, path-based drawing, anti-aliased rendering, gradient fill patterns, images, colors, coordinate-space transformations, and PDF document creation, display, and parsing
b) Core Animation, animating changes in many UIKit view properties and can also be used to implement custom animations. CA本身不是繪制技術(shù),它不提供基礎(chǔ)的shape、image等繪制方案(這里不對CALayer是有shape、image等接口的),它是一項操作、顯示content的技術(shù)。
c) UIKit, Objective-C wrappers for line art, Quartz images, and color manipulations.
5 iOS/macOS的框架結(jié)構(gòu),


6 CoreAnimation
1)CoreAnimation作用
- graphics rendering
- animation infrastructure
2)設(shè)置好動畫參數(shù)后,CA把大部分繪制工作交給GPU加速渲染過程,這樣在不加重CPU負擔的情況下保證了高幀率和動畫流暢性
7 Quartz 2D
Quartz 2D是一個二維繪制引擎,如有必要會利用GPU繪制
8 個人總結(jié)
CoreGraphics是基于CPU的用于繪制圖形(path,shadow,shading,color, anti-aliased),如果有必要它也可以利用GPU加速。CoreAnimation用于提供動畫模型給GPU進行渲染。UIKit和CA都可以進行content繪制,繪制content應(yīng)該是基于CoreGraphics的,然后交由GPU進行渲染顯示。UIKit里的繪制和動畫最終轉(zhuǎn)換成對其layer的操作。
?CA view 合成與GPU圖像合成的區(qū)別
CA is an infrastructure for compositing and manipulating your app’s content in hardware. CA與GPU建立直接通信,這兩個合成是一樣的。
?1)和2)的關(guān)系
? UIKit的繪制是對CoreGraphics的封裝
? UIKit CoreAnimation CoreGraphics,OpenGLES的關(guān)系,分別是基于CPU?GPU?
http://m.itdecent.cn/p/774329cd4bc2
iOS 內(nèi)存管理
1 內(nèi)存操作的OC方法,這些方法不是有OC本身提供,而是由Foundation框架提供

2 (MRC)
[NSMutableArray array]使用Autorelease實現(xiàn),[obj autorelease]會把obj放入pool里,當釋放pool時,會向pool里的所有對象發(fā)送release消息。
- (id)object
{
id obj = [[NSObject alloc] init];
/*
* At this moment, this method has ownership of the object. */
[obj autorelease];
/*
* The object exists, and you don’t have ownership of it. */
return obj;
}

3 (ARC)變量表示符(Ownership qualifiers),一個對象變量必須有個標識符:
1)__strong (default)
id __strong obj = [[NSObject alloc] init]; // ARC
id obj = [[NSObject alloc] init]; // ARC
id obj = [[NSObject alloc] init]; // MRC alloc init 創(chuàng)建并持有對象
// ARC,出作用域自動釋放obj
{
id __strong obj = [[NSObject alloc] init];
}
// MRC
{
id obj = [[NSObject alloc] init];
[obj release];
}
2) __weak(為了解決circular reference, 引用對象被釋放后置為nil)
id __weak obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
The result is:
A: <NSObject: 0x753e180>
B: (null)
3) __unsafe_unretained (引用對象被釋放后不一定為nil)
id __unsafe_unretained obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
The result is:
A: <NSObject: 0x753e180>
B: <NSObject: 0x753e180> // 這個打印是隨機的,會引起crash
4) __autoreleasing
當一個對象不是從alloc/new/copy/mutableCopy方法和init開頭的方法中獲得的,這個對象就會被自動加入到autorelease pool里。(經(jīng)過驗證不加__autoreleasing標記的對象并沒有被放進pool里)
// [NSMutableArray array] 返回的對象會被添加到autorelease pool里,并且被obj持有
@autoreleasepool {
id __strong obj = [NSMutableArray array];
}
// array的實現(xiàn),創(chuàng)建對象并被obj持有,編譯器檢測到對象會傳給調(diào)用者,在出作用域之前便會把對象添加到autorelease pool里
// 這里即使沒有autoreleasing標識符也可以進pool
+ (id) array {
id obj = [[NSMutableArray alloc] init];
return obj;
}

weak對象總是會被添加到autorelease pool里,
id __weak obj1 = obj0; NSLog(@"class=%@", [obj1 class]);
// The above source code is equivalent to:
id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class=%@", [tmp class]);
這里有個優(yōu)化的問題,對于非alloc/new/copy/mutableCopy方法創(chuàng)建的對象。通常調(diào)用objc_autoreleaseReturnValue會把對象加入pool里,但事實上并不總是這樣。如果隨后調(diào)用objc_retainAutoreleasedReturnValue,就會繞過pool。
{
id __strong obj = [NSMutableArray array];
}
等價于:
/* pseudo code by the compiler */
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
+ (id) array {
return [[NSMutableArray alloc] init];
}
等價于:
/* pseudo code by the compiler */
+ (id) array {
id obj = objc_msgSend(NSMutableArray, @selector(alloc));
objc_msgSend(obj, @selector(init));
return objc_autoreleaseReturnValue(obj);
}

4 屬性標識符

?init方法與便利方法的區(qū)別
? 如何把對象放入autorelease pool里 (經(jīng)過驗證只有__autoreleasing修飾和不賦值的[NSArray array]會加入pool里,weak引用不會先加入pool里,poolpage是自動創(chuàng)建的,只跟線程有關(guān))
? 一些回調(diào)block會向當前線程的poolpage里放入很多對象
GCD
1 dispatch queue 種類
下面是系統(tǒng)提供的queue,分為串行主隊列和并行Global隊列
dispatch_get_main_queue();
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

2 dispatch_set_target_queue
通過dispatch_queue_create方法創(chuàng)建的隊列優(yōu)先級是defalut的,用這個方法可以改變隊列的優(yōu)先級,第一個參數(shù)為要改變優(yōu)先級的隊列,第二個為目標優(yōu)先級隊列。
// globalDispatchQueueBackground 是global隊列background優(yōu)先級
dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
這個方法還能做線程依賴,避免并發(fā)執(zhí)行
當下面三個隊列異步執(zhí)行時,任務(wù)是按順序執(zhí)行的。
dispatch_queue_t targetQueue = dispatch_queue_create("test.target.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("test.1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("test.2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue3 = dispatch_queue_create("test.3", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
dispatch_set_target_queue(queue3, targetQueue);
3 dispatch group, wait
用于確定所有請求都成完成在執(zhí)行下一步,dispatch_group_wait用于批量任務(wù)超時處理
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
long result = dispatch_group_wait(group, time);//超時時間,定義等待1s
if (result == 0) {
NSLog(@"Finished!!!");
} else {
NSLog(@"timeout!!!");
}
4 dispatch_barrier_async
如下所示,一共有5個任務(wù)添加到并行隊列queue里,第三個任務(wù)會等待前兩個任務(wù)的完成才執(zhí)行,并且在寫操作執(zhí)行完才會派發(fā)隊列里的其他任務(wù)。
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk1_for_reading);
dispatch_barrier_async(queue, blk_for_writing);
dispatch_async(queue, blk2_for_reading);
dispatch_async(queue, blk3_for_reading);
5 dispatch_sync 會等待隊列里的任務(wù)執(zhí)行完,在此之前阻塞當前線程

6 dispatch_apply
這個方法向一個并行隊列里加入多次任務(wù),任務(wù)的執(zhí)行是并發(fā)的,所有任務(wù)執(zhí)行完之前當前線程阻塞。
// 向queue里加入10個任務(wù)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(5, queue, ^(size_t index) {
NSLog(@"%zu", index);
});
NSLog(@"done");
result:4,1,0,3,2,done
7 dispatch_suspend/dispatch_resume
dispatch_suspend會掛起隊列,這意味著被掛起的隊列不能再執(zhí)行任務(wù),但可以繼續(xù)添加任務(wù),直到resume隊列里的任務(wù)才會繼續(xù)執(zhí)行
8 dispatch_semaphore
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 100000; ++i) {
dispatch_async(queue, ^{
//wait semaphore 不為0則執(zhí)行-1并執(zhí)行任務(wù),還可以做超時處理
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[array addObject:[NSNumber numberWithInt:i]];
dispatch_semaphore_signal(semaphore); // semaphore +1
});
}