【iOS】架構師之路~底層原理五 : (面試題目整理)

1. 一個OC對象佔用多少內存

系統分配了16個字節給NSObject對象(經過malloc_size函數得到)
但NSObject對象內部只使用了8個字節的空間(64bit環境下,能夠經過class_getInstanceSize函數得到)
複製代碼

2. 對象的isa指針指向哪裏?

instance對象的isa指向class對象
class對象的isa指向meta-class對象
meta-class對象的isa指向基類的meta-class對象
複製代碼

3.OC的類信息存放在哪裏?

對象方法、屬性、成員變量、協議信息,存放在class對象中
類方法,存放在meta-class對象中
成員變量的具體值,存放在instance對象
複製代碼

4.iOS用什麼方式實現對一個對象的KVO?(KVO的本質是什麼?)

- 利用RuntimeAPI動態生成一個子類,而且讓instance對象的isa指向這個全新的子類
- 當修改instance對象的屬性時,會調用Foundation的_NSSetXXXValueAndNotify函數
    willChangeValueForKey:
    父類原來的setter
    didChangeValueForKey:
- 內部會觸發監聽器(Oberser)的監聽方法(observeValueForKeyPath:ofObject:change:context:)
複製代碼

5.如何手動觸發KVO?

手動調用willChangeValueForKey:和didChangeValueForKey:
//
- (void)viewDidLoad {
[super viewDidLoad];

    Person *person = [[Person alloc]init];;
    [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    [p willChangeValueForKey:@"name"];
    [p didChangeValueForKey:@"name"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"被觀測對象:%@, 被觀測的屬性:%@, 值的改變: %@\n, 攜帶信息:%@", object, keyPath, change, context);
}
複製代碼

6.直接修改爲員變量會觸發KVO麼?

不會觸發KVO
複製代碼

7.經過KVC修改屬性會觸發KVO麼?

會觸發KVO
KVC在賦值時候,內部會觸發監聽器(Oberser)的監聽方法(observeValueForKeyPath:ofObject:change:context:) 發送通知
複製代碼

8.KVC的賦值和取值過程是怎樣的?原理是什麼?

KVC的全稱是Key-Value Coding,俗稱「鍵值編碼」,能夠經過一個key來訪問某個屬性
調用 setValue:forKey:
setKey,_setKey  ->找到了則進行賦值,未找到調用 accessInstanceVarlableDirctly 是否運行 修改值,返回YES
調用_key, _isKey, key, isKey 進行賦值
複製代碼

9.Category的使用場合是什麼?

- 在不修改原有類代碼的狀況下,爲類添對象方法或者類方法
- 或者爲類關聯新的屬性
- 分解龐大的類文件

使用場合:
- 添加實例方法
- 添加類方法
- 添加協議
- 添加屬性
- 關聯成員變量
複製代碼

10.Category的實現原理

Category編譯以後的底層結構是struct category_t,裏面存儲着分類的對象方法、類方法、屬性、協議信息
在程序運行的時候,runtime會將Category的數據,合併到類信息中(類對象、元類對象中)
複製代碼

11.Category和Class Extension的區別是什麼?

Class Extension在編譯的時候,它的數據就已經包含在類信息中
Category是在運行時,纔會將數據合併到類信息中
複製代碼

12.Category中有load方法嗎?load方法是何時調用的?load 方法能繼承嗎?

- 有load方法
- load方法在runtime加載類、分類的時候調用
- load方法能夠繼承,可是通常狀況下不會主動去調用load方法,都是讓系統自動調用
複製代碼

13. initialize方法如何調用,以及調用時機

- 當類第一次收到消息的時候會調用類的initialize方法
- 是經過 runtime 的消息機制 objc_msgSend(obj,@selector()) 進行調用的
- 優先調用分類的 initialize, 若是沒有分類會調用 子類的,若是子類未實現則調用 父類的
複製代碼

13. load、initialize方法的區別什麼?它們在category中的調用的順序?以及出現繼承時他們之間的調用過程?

- load 是類加載到內存時候調用, 優先父類->子類->分類
- initialize 是類第一次收到消息時候調用,優先分類->子類->父類
- 同級別和編譯順序有關係
- load 方法是在 main 函數以前調用的
複製代碼

14. Category可否添加成員變量?若是能夠,如何給Category添加成員變量?

不能直接給Category添加成員變量,可是能夠間接實現Category有成員變量的效果
Category是發生在運行時,編譯完畢,類的內存佈局已經肯定,沒法添加成員變量(Category的底層數據結構也沒有成員變量的結構)
能夠經過 runtime 動態的關聯屬性
複製代碼

15. block的原理是怎樣的?本質是什麼?

block 本質實際上是OC對象
block 內部封裝了函數調用以及調用環境
複製代碼

16. __block的做用是什麼?有什麼使用注意點?

若是須要在 block 內部修改外部的 局部變量的值,就須要使用__block 修飾(全局變量和靜態變量不須要加__block 能夠修改)

__block 修飾之後,局部變量的數據結構就會發生改變,底層會變成一個結構體的對象,結構內部會聲明 一個 __block修飾變量的成員, 而且將 __block修飾變量的地址保存到堆內存中. 後面若是修改 這個變量的值,能夠經過 isa 指針找到這個結構體,進來修改 這個變量的值;

能夠在 block 內部修改 變量的值
複製代碼

17. block的屬性修飾詞爲何是copy?使用block有哪些使用注意?

block 一旦沒有進行copy操做,就不會在堆上
使用注意:循環引用問題 (外部使用__weak 解決)
複製代碼

17. block在修改NSMutableArray,需不須要添加__block?

若是是操做 NSMutableArray 對象不須要,由於 block 內部拷貝了 NSMutableArray對象的內存地址,實際是經過內存地址操做的
若是 NSMutableArray 對象要從新賦值,就須要加__block
複製代碼

18. Block 內部爲何不能修改局部變量,須要加__block

經過查看Block 源碼,能夠發現, block 內部若是單純使用 外部變量, 會在 block 內部建立一樣的一個變量,而且將 外部變量的值引用過來..(只是將外部變量值拷貝到 block 內部), 內部這個變量和外部 實際已經不要緊了

從另外一方面分析,block 本質也是一個 函數指針, 外部的變量也是一個局部變量,頗有可能 block 在使用這個變量時候,外部變量已經釋放了,會形成錯誤

加了__block 之後, 會將外部變量的內存拷貝到堆中, 內存由 block 去管理.
複製代碼

19.講一下 OC 的消息機制

OC中的方法調用其實都是轉成了objc_msgSend函數的調用,給receiver(方法調用者)發送了一條消息(selector方法名)
objc_msgSend底層有3大階段
消息發送(當前類、父類中查找)、動態方法解析、消息轉發
複製代碼
19.1 消息發送流程
當咱們的一個 receiver(實例對象)收到消息的時候, 會經過 isa 指針找到 他的類對象, 而後在類對象方法列表中查找 對應的方法實現,若是 未找到,則會經過 superClass 指針找到其父類的類對象, 找到則返回,未找打則會一級一級往上查到,最終到NSObject 對象, 若是仍是未找到就會進行動態方法解析

類方法調用同上,只不過 isa 指針找到元類對象;
複製代碼
19.1 動態方法解析機制
當咱們發送消息未找到方法實現,就會進入第二步,動態方法解析: 代碼實現以下

//  動態方法綁定- 實例法法調用
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(run)) {
        Method method = class_getInstanceMethod(self, @selector(test));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

// 類方法調用
+(BOOL) resolveClassMethod:(SEL)sel....
複製代碼

20.消息轉發機制流程

未找到動態方法綁定,就會進行消息轉發階段

// 快速消息轉發- 指定消息處理對象
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(run)) {
        return [Student new];
    }
    return  [super forwardingTargetForSelector:aSelector];
} 

// 標準消息轉發-消息簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if(aSelector == @selector(run))
    {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
   //內部邏輯本身處理 
}
複製代碼

21.什麼是Runtime?平時項目中有用過麼?

Objective-C runtime是一個`運行時`庫,它爲Objective-C語言的動態特性提供支持,咱們所寫的OC代碼在運行時都轉成了runtime相關的代碼,類轉換成C語言對應的結構體,方法轉化爲C語言對應的函數,發消息轉成了C語言對應的函數調用。經過了解runtime以及源碼,能夠更加深刻的瞭解OC其特性和原理

OC是一門動態性比較強的編程語言,容許不少操做推遲到程序運行時再進行
OC的動態性就是由Runtime來支撐和實現的,Runtime是一套C語言的API,封裝了不少動態性相關的函數
平時編寫的OC代碼,底層都是轉換成了Runtime API進行調用
複製代碼

22.runtime具體應用

利用關聯對象(AssociatedObject)給分類添加屬性
遍歷類的全部成員變量(修改textfield的佔位文字顏色、字典轉模型、自動歸檔解檔)
交換方法實現(交換系統的方法)
利用消息轉發機制解決方法找不到的異常問題
複製代碼

23.打印結果分別是什麼?

1.png

[self class] 和 [super class] 都是給當前類返送消息,spuer 表示在父類中查找
[self superClass]  和 [super superclass] 也是也當前類發消息,返回父類
第一個打印:
MJStudent / MJStudent/ MJerson / MJPerson

isKindOfClass 表示對象是否爲當前類或者子類的 類型
isMemberOfClass 表示是否爲當前類的的類型
isMemberOfClass 分爲- 對象方法 和+ 類方法2中
- (bool)isMemberOfClass; 比較的是類對象
+ (bool)isMemberOfClass; 比較的是元類
第二個打印:
1 ,0, 0, 0
複製代碼

24.如下代碼能不能執行成功?若是能夠,打印結果是什麼?

2.png

打印結果: <ViewController: 0x7f9396c16300>
複製代碼

25.講講 RunLoop,項目中有用到嗎?

runloop運行循環,保證程序一直運行,主線程默認開啓
用於處理線程上的各類事件,定時器等
能夠提升程序性能,節約CPU資源,有事情作就作,沒事情作就讓線程休眠

應用範疇:
定時器,事件響應,手勢識別,界面刷新,以及autoreleasePool 等等
複製代碼

26.runloop內部實現邏輯?

3.png

實際上 RunLoop 就是這樣一個函數,其內部是一個 do-while 循環。當你調用 CFRunLoopRun() 時,線程就會一直停留在這個循環裏;直到超時或被手動中止,該函數纔會返回。
複製代碼

27.runloop和線程的關係?

每條線程都有惟一的一個與之對應的RunLoop對象
RunLoop保存在一個全局的Dictionary裏,線程做爲key,RunLoop做爲value
線程剛建立時並無RunLoop對象,RunLoop會在第一次獲取它時建立
RunLoop會在線程結束時銷燬
主線程的RunLoop已經自動獲取(建立),子線程默認沒有開啓RunLoop
複製代碼

28.timer 與 runloop 的關係?

timer 定時器,是基於 runloop 來實現的, runloop 在運行循環當中,監聽到了定製器 就會執行;因此 timer 須要添加到 runloop 中去, 注意子線程的 runloop 默認是不開啓的,若是在子線程執行 timer 須要手動開啓 runloop
複製代碼

29.程序中添加每3秒響應一次的NSTimer,當拖動tableview時timer可能沒法響應要怎麼解決?

將 timer 對象添加到 runloop 中,並修改 runloop 的運行 mode

 NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:nil];
 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
複製代碼

30.runloop 是怎麼響應用戶操做的, 具體流程是什麼樣的?

不明白問題想問什麼?
複製代碼

31.說說runLoop的幾種狀態

添加Observer監聽RunLoop的全部狀態html

4.png

32.runloop的mode做用是什麼?

runloop 只能在一種 mode 下運行, 作不一樣的事情,runloop 會切換到對應的 model 下來執行,默認是  kCFRunLoopDefaultMode 若是視圖滑動再回切換到  UITrackingRunLoopMode,若是須要在多種 mode 下運行則須要手動設置 kCFRunLoopCommonModes;

1. kCFRunLoopDefaultMode:App的默認Mode,一般主線程是在這個Mode下運行
2. UITrackingRunLoopMode:界面跟蹤 Mode,用於 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其餘 Mode 影響
3. UIInitializationRunLoopMode: 在剛啓動 App 時第進入的第一個 Mode,啓動完成後就再也不使用,會切換到kCFRunLoopDefaultMode
4. GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,一般用不到
5. kCFRunLoopCommonModes: 這是一個佔位用的Mode,做爲標記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,並非一種真正的Mode 
複製代碼

33.你理解的多線程?

同一時間,CPU 只能處理理一條線程, 只有一條線程在⼯工做 多線程併發執行,實際上是 CPU 快速的在多條線程之間調度(切換) 若是 CPU 調度線程的時間⾜足夠快, 就形成了多線程併發執⾏的假象

優點
充分發揮多核處理器的優點,將不一樣線程任務分配給不一樣的處理器,真正進入「⾏行 計算」狀態
弊端 
新線程會消耗內存控件和cpu時間,線程太多會下降系統行性能。
複製代碼

34.iOS的多線程方案有哪幾種?你更傾向於哪種?

5.png

傾向於GCD ,簡單靈活,使用方便
複製代碼

35.你在項目中用過 GCD 嗎?

使用過

GCD中有2個用來執行任務的函數
用同步的方式執行任務
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:隊列
block:任務

用異步的方式執行任務
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
複製代碼

36.GCD 的隊列類型

GCD的隊列能夠分爲2大類型
併發隊列(Concurrent Dispatch Queue)
可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務)
併發功能只有在異步(dispatch_async)函數下才有效

串行隊列(Serial Dispatch Queue)
讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)
複製代碼

37.說一下 OperationQueue 和 GCD 的區別,以及各自的優點

1> GCD是純C語⾔言的API,NSOperationQueue是基於GCD的OC版本封裝
2> GCD只⽀支持FIFO的隊列列,NSOperationQueue能夠很⽅方便便地調整執⾏行行順 序、設 置最⼤大併發數量量
3> NSOperationQueue能夠在輕鬆在Operation間設置依賴關係,⽽而GCD 須要寫很 多的代碼才能實現
4> NSOperationQueue⽀支持KVO,能夠監測operation是否正在執⾏行行 (isExecuted)、 是否結束(isFinished),是否取消(isCanceld)
5> GCD的執⾏行行速度⽐比NSOperationQueue快 任務之間不不太互相依賴:GCD 任務之間 有依賴\或者要監放任務的執⾏行行狀況:NSOperationQueue
複製代碼

38.線程安全的處理手段有哪些?

1.加鎖
2.同步執行
複製代碼

39.OC你瞭解的鎖有哪些?在你回答基礎上進行二次提問;

os_unfair_lock  ios10 開始
OSSpinLock      ios10 廢棄
dispatch_semaphore   建議使用,性能也比較好
dispatch_mutex
dispatch_queue   串行
NSLock  對 mutex 封裝
@synchronized 性能最差
複製代碼

40.追問一:自旋和互斥對比?

什麼狀況使用自旋鎖比較划算?
預計線程等待鎖的時間很短
加鎖的代碼(臨界區)常常被調用,但競爭狀況不多發生
CPU資源不緊張
多核處理器

什麼狀況使用互斥鎖比較划算?
預計線程等待鎖的時間較長
單核處理器
臨界區有IO操做
臨界區代碼複雜或者循環量大
臨界區競爭很是激烈   
複製代碼

41.追問二:使用以上鎖須要注意哪些?

注意死鎖
在串行隊列使用同步,容易形成死鎖
複製代碼

42.追問三:用C/OC/C++,任選其一,實現自旋或互斥?口述便可!

兩種鎖的加鎖原理:

互斥鎖:線程會從sleep(加鎖)——>running(解鎖),過程當中有上下文的切換,cpu的搶佔,信號的發送等開銷。

自旋鎖:線程一直是running(加鎖——>解鎖),死循環檢測鎖的標誌位,
複製代碼

43.請問下面代碼的打印結果是什麼?

6.png

打印 1,3
performSelector after 是基於 timer 定製器,定時器又是基於 runloop 實現的
任務2在子線程中,子線程默認 runloop 是不開啓的,因此不執行2
複製代碼

44.請問下面代碼的打印結果是什麼?

7.png

打印1
start 執行完,線程就銷燬了.任務 test 無法執行了
複製代碼

45.使用CADisplayLink、NSTimer有什麼注意點?

CADisplayLink 保證調用頻率和刷幀頻率一直,60FPS, 不用設置時間間隔,每秒鐘60次
    可使用 proxy 代理解決循環引用

    CADisplayLink、NSTimer會對target產生強引用,若是target又對它們產生強引用,那麼就會引起循環引用
複製代碼

46.介紹下內存的幾大區域

低地址-> 高地址
保留->代碼段->數據段(字符串常量,已初始化全局數據,未初始化數據)>堆->棧內存-> 內核區域
代碼段: 編譯以後的代碼
數據段: 字符串常量,已經初始化的全局變量,或者靜態變量,未初始化的全局變量,靜態變量
堆 (低>高)  經過 alloc malloc calloc 動態分配的內存

棧 (高地址 從 低地址)  函數調用開銷()
複製代碼

47.講一下你對 iOS 內存管理的理解

在iOS中,使用引用計數來管理OC對象的內存

一個新建立的OC對象引用計數默認是1,當引用計數減爲0,OC對象就會銷燬,釋放其佔用的內存空間

調用retain會讓OC對象的引用計數+1,調用release會讓OC對象的引用計數-1

內存管理的經驗總結
當調用alloc、new、copy、mutableCopy方法返回了一個對象,在不須要這個對象時,要調用release或者autorelease來釋放它
想擁有某個對象,就讓它的引用計數+1;不想再擁有某個對象,就讓它的引用計數-1

能夠經過如下私有函數來查看自動釋放池的狀況
extern void _objc_autoreleasePoolPrint(void);
複製代碼

48.ARC 都幫咱們作了什麼?

LLVM + Runtime 會爲咱們代碼自動插入 retain 和 release 以及 autorelease等代碼,不須要咱們手動管理
複製代碼

49.weak指針的實現原理

Runtime維護了一個weak表,用於存儲指向某個對象的全部weak指針。weak表實際上是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象的地址)數組。

runtime對註冊的類, 會進行佈局,對於weak對象會放入一個hash表中。 用weak指向的對象內存地址做爲key,當此對象的引用計數爲0的時候會dealloc,假如weak指向的對象內存地址是a,那麼就會以a爲鍵, 在這個weak表中搜索,找到全部以a爲鍵的weak對象,從而設置爲nil。
複製代碼

50.autorelease對象在什麼時機會被調用release

iOS在主線程的Runloop中註冊了2個Observer
-第1個Observer監聽了kCFRunLoopEntry事件,會調用objc_autoreleasePoolPush()
-第2個Observer
    監聽了kCFRunLoopBeforeWaiting事件,會調用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
    監聽了kCFRunLoopBeforeExit事件,會調用objc_autoreleasePoolPop()

    objc_autoreleasePoolPop()調用時候回給 pool 中的對象發送一次 release 消息
複製代碼

51.方法裏有局部對象, 出了方法後會當即釋放嗎

若是是普通的 局部對象 會當即釋放
若是是放在了 autoreleasePool 自動釋放吃,則會等runloop 循環,進入休眠前釋放
複製代碼

52.思考如下2段代碼能發生什麼事?有什麼區別?

8.png

第一個內存會暴漲,self.name 會不停的建立
第二個內存固定,會使用 Tagged Pointer 將值存在地址中
複製代碼

53.你在項目中是怎麼優化內存的?

內存優化能夠從 內存泄漏 和 內存開銷 2方面入口

- 減小內存泄露
  可使用靜態分析以及instruments的leaks 分析
  注意 NStimer 以及 block ,delegate 等的使用,避免循環引用

- 下降內存使用峯值
  1. 關於圖片加載佔用內存問題:imageNamed: 方法會在內存中緩存圖片,用於經常使用的圖片。
   imageWithContentsOfFile: 方法在視圖銷燬的時候會釋放圖片佔用的內存,適合不經常使用的大圖等。

  2.tableView cell 儘可能使用重用機制,減小額外的開銷
  3.tableView 列表圖片展現儘可能使用縮略圖
  4.延遲加載 對象,節約內存開銷
  5.避免短期大量建立對象,配合 autoreleasePool 減小內存峯值
  6.重用大開銷對象,好比: NSDateFormatter和NSCalendar
  7.加載 html 儘可能使用 wkwebView
  8.單例使用不易過多
  9.線程最大併發數
複製代碼

54.優化你是從哪幾方面着手?

卡頓優化
啓動優化
耗電量優化
app 瘦身

CPU 佔用率、 內存使用狀況、網絡情況監控、啓動時閃退、卡頓、FPS、使用時崩潰、耗電量監控、流量監控....
複製代碼

55.列表卡頓的緣由可能有哪些?你平時是怎麼優化的?

1.最經常使用的就是cell的重用, 註冊重用標識符
   若是不重用cell時,每當一個cell顯示到屏幕上時,就會從新建立一個新的cell;
   若是有不少數據的時候,就會堆積不少cell。
   若是重用cell,爲cell建立一個ID,每當須要顯示cell 的時候,都會先去緩衝池中尋找可循環利用的cell,若是沒有再從新建立cell

2.避免cell的從新佈局
   cell的佈局填充等操做 比較耗時,通常建立時就佈局好
   如能夠將cell單獨放到一個自定義類,初始化時就佈局好

3.提早計算並緩存cell的屬性及內容
    當咱們建立cell的數據源方法時,編譯器並非先建立cell 再定cell的高度
    而是先根據內容一次肯定每個cell的高度,高度肯定後,再建立要顯示的cell,滾動時,每當cell進入憑虛都會計算高度,提早估算高度告訴編譯器,編譯器知道高度後,緊接着就會建立cell,這時再調用高度的具體計算方法,這樣能夠方式浪費時間去計算顯示之外的cell

4.減小cell中控件的數量
   儘可能使cell得佈局大體相同,不一樣風格的cell可使用不用的重用標識符,初始化時添加控件,
   不適用的能夠先隱藏

5.不要使用ClearColor,無背景色,透明度也不要設置爲0
   渲染耗時比較長

6.使用局部更新
   若是隻是更新某組的話,使用reloadSection進行局部更新

7.加載網絡數據,下載圖片,使用異步加載,並緩存

8.少使用addView 給cell動態添加view

9.按需加載cell,cell滾動很快時,只加載範圍內的cell

10.不要實現無用的代理方法,tableView只遵照兩個協議

11.緩存行高:estimatedHeightForRow不能和HeightForRow裏面的layoutIfNeed同時存在,這二者同時存在纔會出現「竄動」的bug。因此個人建議是:只要是固定行高就寫預估行高來減小行高調用次數提高性能。若是是動態行高就不要寫預估方法了,用一個行高的緩存字典來減小代碼的調用次數便可

12.不要作多餘的繪製工做。在實現drawRect:的時候,它的rect參數就是須要繪製的區域,這個區域以外的不須要進行繪製。例如上例中,就能夠用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判斷是否須要繪製image和text,而後再調用繪製方法。

13.預渲染圖像。當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在bitmap context裏先將其畫一遍,導出成UIImage對象,而後再繪製到屏幕;

14.使用正確的數據結構來存儲數據。
複製代碼

56.app 啓動優化

1\. pre-main 以前

    * 排查無用的動態庫(按期清理)
    * 減小ObjC類(項目中不適用的的庫,廢棄的代碼等)、方法(selector)、分類(category)的數量、無用的庫
    * 少在類的+load方法裏作事情,儘可能把這些事情推遲到+initiailize1.

2\. main 函數以後的 didFinishLaunchingWithOptions 加載完以前

    * 不影響用戶體驗的操做,作延遲加載,不要所有放在  didFinishLaunchingWithOptions中去作
    * 版本更新,一些三方初始化,不須要在 didFinishLaunchingWithOptions 初始化的放到,界面展現完之後再初始化
    * 一些網絡請求延遲 請求..
    * 一些業務邏輯延遲 加載
    * 初始化第三方 SDK
    * 配置 APP 運行須要的環境
    * 本身的一些工具類的初始化
複製代碼

57.app 耗電量優化

1.不要頻繁的刷新頁面,能刷新1行cell最好只刷新一行,儘可能不要使用reloadData.
2.選擇正確的集合
    NSArray,使用index來查找很快(插入和刪除很慢)
    字典,使用鍵來查找很快
    NSSets,是無序的,用鍵查找很快,插入/刪除很快
3.少用運算得到圓角,必需要用圓角的話,不如把圖片自己就作成圓角
4.懶加載,不要一次性建立全部的subview,而是須要時才建立.
5.重用機制
6.圖片處理
    圖片與imageView相同大小,避免多餘運算
    可使用整副的圖片,增長應用體積,可是節省CPU
    可調大小的圖片,能夠省去一些沒必要要的空間
    CALayer,CoreGraphics,甚至OpenGL來繪製,消耗CPU
7.cache,cache,cache(緩存全部須要的)
    服務器相應結果的緩存(圖片)
    複雜計算結果的緩存(UITableView的行高)
8.儘可能少用透明或半透明,會產生額外的運算.

9.使用ARC減小內存失誤,dealloc須要重寫並對屬性置爲nil

10.避免龐大的xib,storyBoard,儘可能使用純代碼開發

CPU層面

1.Timer的時間間隔不宜過短,知足需求便可
2.線程適量,不宜過多,不要阻塞主線程
3.優化算法,減小循環次數
4.定位和藍牙按需取用,定位以後要關閉或下降定位頻率
5.一些硬件的使用,不使用就關掉
複製代碼

58.app 的包瘦身

9.png

59.講講 MVC、MVVM、MVP,以及你在項目裏具體是怎麼寫的?

MVC  Model-view-controller 數據-視圖-控制器     
通常控制器用於管理數據和視圖, 數據和視圖交互都是經過控制器來進行的.視圖和數據進行了解耦, 可是咱們平常使用常常會將模型綁定給視圖.模型封裝在視圖內部,外部不用管理視圖內部業務邏輯,這數據 mvc 的變種, 控制器只給視圖模型數據就行了. 缺點是視圖和 模型有耦合;

MVVM Model-view-viewModel  模型-視圖-視圖模型
view 和 model 的交互經過viewmodel 來進行交互,實現數據的雙向綁定

MVP  Model-view - Presenter  模型-視圖-主持人

view 和 model 的交互經過Presenter,controller經過Presenter來管理 model 和 View
複製代碼

60.你本身用過哪些設計模式?

結合本身項目來說吧
複製代碼

61.通常開始作一個項目,你的架構是如何思考的?

根據模塊,使用 mvc 功能劃分..結合本身項目講比較容易
涉及到東西也比較多,比較雜,大到整個項目架構,小到一個 view 的架構;沒具體的答案
複製代碼

參考:iOS底層原理班(下)/OC對象/關聯對象/多線程/內存管理/性能優化ios

相關文章
相關標籤/搜索