iOS基礎(chǔ)知識

1. load方法和initialize方法

相同點(diǎn)

  • 在不考慮開發(fā)者主動使用的情況下,系統(tǒng)最多會調(diào)用一次
  • 如果父類和子類都被調(diào)用,父類的調(diào)用一定在子類之前
  • 都是為了應(yīng)用運(yùn)行提前創(chuàng)建合適的運(yùn)行環(huán)境
  • 在使用時都不要過重地依賴于這兩個方法,除非真正必要

load

  • 調(diào)用時間早于initialize,main函數(shù)之前,不會觸發(fā)initialize的調(diào)用
  • 對于有依賴關(guān)系的類,要確保被依賴類的load優(yōu)先調(diào)用
  • 沒有l(wèi)oad方法的實(shí)現(xiàn),不會調(diào)用父類的的load方法
  • Category的load也會收到調(diào)用,順序在主類之后
  • Method Swizzleu一般會放在load中執(zhí)行

initialize

  • 懶加載,第一次主動使用類時調(diào)用
  • 子類不實(shí)現(xiàn)initialize方法,會把父類的實(shí)現(xiàn)繼承過來調(diào)用一遍
  • 都是線程安全的,不要再使用鎖

2.block

數(shù)據(jù)結(jié)構(gòu)

struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};
struct Block_layout {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

類型

  • _NSConcreteGlobalBlock 全局的靜態(tài) block,不會訪問任何外部變量。
  • _NSConcreteStackBlock 保存在棧中的 block,當(dāng)函數(shù)返回時會被銷毀。
  • _NSConcreteMallocBlock 保存在堆中的 block,當(dāng)引用計數(shù)為 0 時會被銷毀。

變量的復(fù)制

  • block外變量的引用,是復(fù)制到數(shù)據(jù)結(jié)構(gòu)中訪問
  • __block修飾的外部變量,是復(fù)制其引用地址來實(shí)現(xiàn)訪問

ARC和MRC下的block

配置在棧上的Block也就是NSStackBlock類型的Block,如果其所屬的變量作用域結(jié)束該Block就會廢棄。這個時候如果繼續(xù)使用該Block,就應(yīng)該使用copy方法,將NSStackBlock拷貝為NSMallocBlock。當(dāng)NSMallocBlock的引用計數(shù)變?yōu)?,該NSMallocBlock就會被釋放。
如果是非ARC環(huán)境,需要顯式的執(zhí)行copy或者antorelease方法。
而當(dāng)ARC有效的時候,實(shí)際上大部分情況下編譯器已經(jīng)為我們做好了,自動的將Block從棧上復(fù)制到堆上。包括以下幾個情況:

  1. Block作為返回值時,類似在非ARC的時候,對返回值Block執(zhí)行[[returnedBlock copy] autorelease];
  2. 方法的參數(shù)中傳遞Block時
  3. Cocoa框架中方法名中還有useringBlock等時
  4. GCD相關(guān)的一系列API傳遞Block時

對于非ARC下,為了防止循環(huán)引用,我們使用__block來修飾在Block中使用的對象。
對于ARC下,為了防止循環(huán)引用,我們使用__weak來修飾在Block中使用的對象。

循環(huán)引用和野指針

block和對象互相強(qiáng)引用,引起引用循環(huán),使用弱引用打破循環(huán)。block使用的對象被提前釋放,產(chǎn)生了野指針,會引起crash,要注意對象的生命周期。

參考鏈接
談Objective-C block的實(shí)現(xiàn)
正確使用Block避免Cycle Retain和Crash

3.ARC

ARC是編譯特性,不是垃圾回收,本質(zhì)還是計數(shù)式內(nèi)存管理,在ARC特性下有4種與內(nèi)存管理息息相關(guān)的變量所有權(quán)修飾符值得我們關(guān)注:

變量所有權(quán)修飾符 屬性修飾符
__strong copy retain strong
__weak weak
__autoreleasing N/A
__unsafe_unretaied assign unsafe_unretained

__autoreleasing

在 ARC 模式下,我們不能顯示的使用 autorelease 方法了

__unsafe_unretained

ARC 是在 iOS5 引入的,而 __unsafe_unretained 這個修飾符主要是為了在 ARC 剛發(fā)布時兼容 iOS4 以及版本更低的系統(tǒng),因?yàn)檫@些版本沒有弱引用機(jī)制

關(guān)于 Toll-Free Bridging

在 MRC 時代,由于 Objective-C 類型的對象和 Core Foundation 類型的對象都是相同的 release 和 retain 操作規(guī)則,所以 Toll-Free Bridging 的使用比較簡單,但是自從切換到 ARC 后,Objective-C 類型的對象內(nèi)存管理規(guī)則改變了,而 Core Foundation 依然是之前的機(jī)制,換句話說,Core Foundation 不支持 ARC。是蘋果在引入 ARC 之后對 Toll-Free Bridging 的操作也加入了對應(yīng)的方法與修飾符,用來指明用哪種規(guī)則管理內(nèi)存,或者說是內(nèi)存管理權(quán)的歸屬。這些方法和修飾符分別是:

  • __bridge(修飾符)-- 只是聲明類型轉(zhuǎn)變,但是不做內(nèi)存管理規(guī)則的轉(zhuǎn)變。
  • __bridge_retained(修飾符) or CFBridgingRetain(函數(shù))-- 內(nèi)存管理的責(zé)任由原來的 Objective-C 交給Core Foundation 來處理,也就是,將 ARC 轉(zhuǎn)變?yōu)?MRC
  • __bridge_transfer(修飾符) or CFBridgingRelease(函數(shù))-- 內(nèi)存管理的責(zé)任由 Core Foundation 轉(zhuǎn)交給 Objective-C,即將管理方式由 MRC 轉(zhuǎn)變?yōu)?ARC。

參考鏈接:
iOS ARC 內(nèi)存管理要點(diǎn)

4.RunLoop

概念

線程能隨時處理事件但并不退出的模型通常被稱為Event Loop,RunLoop實(shí)際上是一個對象,這個對象管理了其需要處理的事件和消息,并提供了一個入口函數(shù)來執(zhí)行上面 Event Loop 的邏輯。線程執(zhí)行了這個函數(shù)后,就會一直處于這個函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中,直到這個循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。

和線程的關(guān)系

RunLoop和線程一一對應(yīng),RunLoop的創(chuàng)建發(fā)生在線程第一次獲取時,只能在線程內(nèi)獲取自身的RunLoop(主線程除外)。蘋果不允許直接創(chuàng)建 RunLoop,它只提供了兩個自動獲取的函數(shù):CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。

相關(guān)類

CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source/Timer/Observer。每次調(diào)用 RunLoop 的主函數(shù)時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode。如果需要切換 Mode,只能退出 Loop,再重新指定一個 Mode 進(jìn)入。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響。

Mode

系統(tǒng)默認(rèn)注冊了5個Mode:

  1. kCFRunLoopDefaultMode: App的默認(rèn) Mode,通常主線程是在這個 Mode 下運(yùn)行的。
  2. UITrackingRunLoopMode: 界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響。
  3. UIInitializationRunLoopMode: 在剛啟動 App 時第進(jìn)入的第一個 Mode,啟動完成后就不再使用。
  4. GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到。
  5. kCFRunLoopCommonModes: 這是一個占位的 Mode,沒有實(shí)際作用。

參考鏈接
深入理解RunLoop

5.UIView

UIView繼承于UIResponder類,因此它主要表達(dá)了兩個意思
1.可視(CALayer)
2.可互交(UIResponder)
每個UIView都有一個隱式層(implicit Layer),View本身就是這個隱式層的Delegate.
Layer又有兩部分組成。present layer和Model layer.
present layer表示了中間的過程狀態(tài),而Model layer則表示了起始和結(jié)束狀態(tài)

loadView

loadView在View為nil時調(diào)用,早于ViewDidLoad,通常用于代碼實(shí)現(xiàn)控件,收到內(nèi)存警告時會再次調(diào)用。loadView默認(rèn)做的事情是:加載nib。如果你想自己創(chuàng)建View對象,那么可以重載這個方法。

UIWindow

  1. UIWindow是一種特殊的UIView,通常在一個app中至少會有一個UIWindow。
  2. iOS程序啟動完畢后,創(chuàng)建的第一個視圖控件就是UIWindow,接著創(chuàng)建控制器的View,最后將控制器的View添加到UIWindow上,于是控制器的View就顯示在屏幕上了。
  3. 一個iOS程序之所以能顯示在屏幕上,完全是因?yàn)樗蠻IWindow,也就是說,沒有UIWindow就看不到任何UI界面。
  4. 狀態(tài)欄和鍵盤都是特殊的UIWindow。

UIWindow有三個層級,分別是Normal,StatusBar,Alert。

keyWindow是指定的用來接收鍵盤以及非觸摸類的消息,而且程序中每一個時刻只能有一個window是keyWindow。

6.沙盒和bundle

沙盒目錄結(jié)構(gòu)

  • Application:存放程序源文件,上架前經(jīng)過數(shù)字簽名,上架后不可修改
  • Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù),這里不能存緩存文件,否則上架不被通過
    Library
  • Caches:存放體積大又不需要備份的數(shù)據(jù),SDWebImage緩存路徑就是這個
    Preference:設(shè)置目錄,iCloud會備份設(shè)置信息
  • tmp:存放臨時文件,不會被備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能

App Bundle 里面有什么

  • Info.plist:此文件包含了應(yīng)用程序的配置信息.系統(tǒng)依賴此文件以獲取應(yīng)用程序的相關(guān)信息
  • 可執(zhí)行文件:此文件包含應(yīng)用程序的入口和通過靜態(tài)連接到應(yīng)用程序target的代碼
  • 資源文件:圖片,聲音文件一類的
  • 其他:可以嵌入定制的數(shù)據(jù)資源

7.屬性

修飾符

  • atomic,nonatomic -- 原子性
  • readonly,readwrite -- 訪問權(quán)限
  • assign,strong,weak,copy -- ARC內(nèi)存管理
  • assign,retain,copy -- MRC內(nèi)存管理
  • setter=,getter= -- 指定方法名稱

assign和weak的區(qū)別

assign修飾的數(shù)據(jù)內(nèi)存由系統(tǒng)清理,對于基礎(chǔ)數(shù)據(jù)類型,生存周期為整個棧周期,可以由棧處理。修飾對象時,如果這個對象被其他過程釋放(即指向的堆內(nèi)存被釋放),對象的指針地址依然存在,形成野指針。weak不能修飾基礎(chǔ)類型數(shù)據(jù),修飾對象時,如果對象被釋放,指針會自動置為nil。

實(shí)現(xiàn)原理

在普通的OC對象中,@property就是編譯器自動幫生成一個私有的成員變量和setter與getter方法的聲明和實(shí)現(xiàn)

protocol 和 category

  1. 在protocol中使用property只會生成setter和getter方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象的實(shí)現(xiàn)該屬性
  2. category 使用 @property 也是只會生成setter和getter方法的聲明,如果我們真的需要給category增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時的兩個函數(shù)

objc_setAssociatedObject
objc_getAssociatedObject

8.cocoapods原理

  • 將所有的依賴庫都放到另一個名為 Pods 項(xiàng)目中
  • Pods 項(xiàng)目最終會編譯成一個名為 libPods.a 的文件,主項(xiàng)目只需要依賴這個 .a 文件即可。這樣,依賴庫源碼管理工作都從主項(xiàng)目移到了 Pods 項(xiàng)目中。
  • 對于資源文件,CocoaPods 提供了一個名為 Pods-resources.sh 的 bash 腳本,該腳本在每次項(xiàng)目編譯的時候都會執(zhí)行,將第三方庫的各種資源文件復(fù)制到目標(biāo)目錄中。
  • CocoaPods 通過一個名為 Pods.xcconfig 的文件來在編譯時設(shè)置所有的依賴和參數(shù)。

9. Instruments常用功能

  1. Time Profiler:性能分析
  2. Zombies:檢查是否訪問了僵尸對象
  3. Allocations:用來檢查內(nèi)存,寫算法的那批人也用這個來檢查
  4. Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露

10.nil / Nil / NULL / NSNull

標(biāo)志 含義
NULL (void *)0 C指針的字面零值
nil (id)0 Objective-C對象的字面零值
Nil (Class)0 Objective-C類的字面零值
NSNull [NSNull null] 用來表示零值的單獨(dú)的對象

to be continued

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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