爲了以後博客的進行,本篇博客咱們就來聊一下ReactiveSwift框架中的Lifetime類的具體實現。從Lifetime這個名字中咱們就這道,就是生命週期。在ReactiveSwift中使用Lifetime來標記一個對象的生命週期,其實主要功能仍是將對象的deinit()析構函數經過發送信號量將其回調出來。接下來咱們就來看一下Lifetime類的實現。Lifetime類與Event和Observer類似,也是比較原子性的類,以原子組件的形式存在於ReactiveSwift中。html
下方咱們會先給出一個Lifetime的使用示例,而後根據示例的輸出結果來看一下Lifetime的具體代碼實現,以及工做原理。git
1、Lifetime使用實例github
針對Lifetime的特性,咱們給出了下方的示例。固然ReactiveSwift官網上是沒有關於Lifetime的單獨示例的,由於Lifetime不單獨的對外服務。下方就是咱們對Lifetime類而寫的示例。設計模式
一、lifetime()方法實現閉包
首先咱們來看一下下方的lifetime()方法。。首先經過Lifetime類中的make()工廠方法建立了一個Lifetime的對象和該對象對應的token。而且lifetime()方法在調用時,須要一個引用參數tokenRef,也就是說tokenRef是inout類型的參數,經過tokenRef參數能夠把make()所返回的token傳到函數外部。框架
而後使用lifetime對象的observeEnded()方法來添加兩個觀察者。後邊緊跟着的尾隨閉包是token被釋放時所執行的閉包塊。由於lifetime對象除了在lifetime()方法中使用到,再也沒有其餘地方的引用了,根據ARC中Strong類型的特色,因此在lifetime()方法調用結束後lifetime對象就會被釋放掉。因此咱們在lifetime()函數的結尾處給出了「lifetime將要被釋放」的Log。函數
而lifetime()方法中的token對象經過tokenRef這個inout類型的參數被方法以外的做用域使用到,因此在lifetime()方法調用結束後token所對應的堆空間並不會被釋放。post
二、lifetime()方法的調用url
在tapLifetimeButton()方法中,咱們對上述的lifetime()方法進行了調用。首先咱們聲明瞭一個類型爲Any?的tokenRef變量,該變量在調用lifetime()函數時做爲參數傳給lifetime()方法。也就是說tokenRef變量引用了lifetime()方法中的token對象所對應的堆空間。spa
當lifetime()被調用後,由於lifetime()中的lifetime對象所對應的堆空間只用在lifetime()的做用域中被引用到,因此當該方法執行完畢後,lifetime所對應的堆空間會當即被釋放掉。
當tokenRef被置爲nil後,token所對應的堆空間也會被當即釋放掉。在token被釋放執行token對應的析構函數時,會給那些經過lifetime的observeEnd()方法添加的觀察者發送被析構的消息。因此token被釋放時,會執行observeEnd()方法的尾隨閉包。
三、運行結果
下方截圖就是上述示例的運行結果,咱們能夠根據下方的輸出結果與上述的代碼實現進行對比。從輸出結果中咱們容易知道,lifetime對象是在lifetime()方法調用執行後所釋放的。而在lifetime()方法中所分配的token對象所對應的堆空間是在tokenRef被置爲nil時所釋放的,在釋放以前像觀察lifetime的生命週期的觀察者來發送消息。
從運行結果來看,Lifetime這個生命週期的類,本質上是經過token來標示一個對象的生命週期的,和Lifetime對象的釋放是沒有什麼直接關係。稍後,咱們聊Token類以及Lifetime類時,會一目瞭然。
2、Lifetime中的內部類Token
看完Lifetime的使用示例,咱們來看一下Lifetime的內部代碼實現。在Lifetime類的內部定義個了一個Token類。Token類的對象會在Lifetime中使用到,稍後會給出Token的使用方式。接下來咱們就先來看看這個Lifetime類內部的Token類的代碼實現。
Token類的實現比較簡單,一句話歸納Token的功能:其中使用了Signal的pipe方法建立了一個ended信號量,並獲取到了ended信號量發送事件的endedObserver,而後在deinit析構函數中使用endedObserver的sendCompleted()的方法發送Complete事件。上這句話就歸納了Token中的所有功能。
下方就是Token類的代碼實現,其中有一點須要咱們注意的是在Token的ended信號量所發送的Value值的類型是一個無參閉包。在以後的內容中,用到的時候在介紹。
3、Lifetime的ended屬性和構造器
聊完Token的代碼實現,咱們就來聊一下Lifetime中的對象屬性以及構造器。在Lifetime類中只有一個對象屬性,那就是ended信號量。該信號量的類型也是一個能夠發送無參無返回值的閉包的Value。Lifetime的構造器主要就是給ended賦值。具體代碼以下所示。
4、Lifetime的便利構造器、工廠方法以及empty靜態屬性
一、Lifetime的便利構造器
接下來咱們就來看一下Lifetime的便利構造器。下方代碼片斷中被convenience關鍵字修飾的就是Lifetime的便利構造器。該便利構造器的參數是一個Token類型的對象,而在便利構造器中調用了Lifetime的構造器,將Token對象的ended信號量傳給了Lifetime的構造器。因此Lifetime中的ended信號量其實就是Token對象中的ended信號量。
二、Lifetime的工廠方法
聊完Lifetime的便利構造器後,咱們就來聊一下Lifetime的工廠方法。咱們在以前的博客中《設計模式(四):從「兵工廠」中探索簡單工廠、工廠方法和抽象工廠模式》詳細的介紹了工廠模式。而下方代碼片斷中的make()靜態方法在Lifetime類中所扮演的角色就是工廠方法,負責建立Lifetime類的對象。在make()方法中主要作了兩件事情,一個是實例化了一個Token對象token,而後將token傳給Lifetime的便利構造器。最後將token以及Lifetime的便利構造器所建立的Lifetime類的對象以元組的形式進行返回。具體代碼以下所示。
三、Lifetime的empty靜態計算屬性
Lifetime的empty靜態計算屬性類似於Signal的empty靜態計算屬性,從其實現代碼咱們能夠看出empty所建立的Lifetime對象中的ended信號量是一個Signal.empty類型的信號量。也就是說empty所建立的Lifetime對象是一個已經結束的生命週期。具體代碼以下。
5、observeEnded()方法實現
接下來咱們來看一下observeEnded()方法的代碼實現。該方法的主要目的就是往ended信號量中的Bag容器中添加觀察者的。當觀察者收到的事件是isTerminating時,會執行observeEnded()方法所提供的尾隨閉包。
而這個endend信號量本質上就是token對象中的endend信號量。當token對象被析構時,會在token的析構函數中調用endend信號量發送信號的endendObserver的sendComplete()方法來發送complete事件,也就是上述代碼在Token類的deinit方法中所做的事情。
6、Lifetime執行原理圖
下方是Lifetime、Token、Signal、Observer間的執行關係圖。在Lifetime類中,token起着相當重要的做用。Lifetime的工做原理中實際上是使用Token的對象的生命週期來表示一個對象的生命週期的。若是Lifetime的對象空間被釋放了,可是Token對象所對應的堆空間任然存在,那麼Lifetime所對應的Object的生命週期任然再延續,這一點從上面的代碼示例中能夠明確看出。
仍是那句話,本質上是使用Token對象的生命週期來表示一個對象的Lifetime。
今天的博客就先到這兒,下篇博客咱們會繼續解析ReactiveSwift框架中的其餘內容。
上述代碼github分享地址:https://github.com/lizelu/TipSwiftForRac 。