ios開發(fā)中的設計模式,ios開發(fā)中的設計模式在哪

iOS中常用的幾種設計模式

代理模式完成委托方交給的任務,委托方有一些任務自己不想完成,但是還需要要實現(xiàn),則將該任務存放到協(xié)議中,由代理完成.但是代理并不會主動的執(zhí)行任務,需要委托方通知代理。

專注于為中小企業(yè)提供成都做網(wǎng)站、網(wǎng)站制作服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)嘉魚免費做網(wǎng)站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉變。

觀察者模式本質上是一種發(fā)布-訂閱模型,用以消除具有不同行為的對象之間的耦合,通過這一模式,不同對象可以協(xié)同工作,同時它們也可以被復用于其他地方Observer從Subject訂閱通知,ConcreteObserver實現(xiàn)重現(xiàn)ObServer并將其重載其update方法。

單例模式可以保證App在程序運行中,一個類只有唯一個實例,從而做到節(jié)約內(nèi)存。

在整個App程序中,這一份資源是共享的。

提供一個固定的實例創(chuàng)建方法。

策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。

iOS常用設計模式

代理模式:完成委托方的任務,需要聲明代理對象和指定代理,相對于block,在需要傳遞參數(shù)的傳值時優(yōu)先考慮代理。

代理是一對一的關系(1個對象只能通知1個對象發(fā)生了什么事)。

應用場景:不同類之間的傳值與回調。

觀察者模式(通知機制,KVO機制):觀察者模式本質上是一種發(fā)布-訂閱模型,用以消除具有不同行為的對象之間的耦合,通過這一模式,不同對象可以協(xié)同工作。

通知是一對多的關系(1個通知可以發(fā)送給多個通知接受對象)。

應用場景:監(jiān)聽設備狀態(tài),自定義鍵盤時監(jiān)聽鍵盤的彈出和隱藏。

單例模式:可以保證App在程序運行中,一個類只有唯一個實例。

系統(tǒng)中的單例:UIApplication(應用程序實例)、NSNotificationCenter(消息中心)、NSFileManager(文件管理)、NSUserDefaults(應用程序設置)、NSURLCache(請求緩存)等。

應用場景:功能集中管理的模塊可以封裝為單例,方便外界調用。

策略模式:定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。

MVC(Model View Controller):

model:數(shù)據(jù)層

view:視圖層,負責頁面展示

Controller:控制視圖層與數(shù)據(jù)層的關聯(lián),

MVVM(model view viewModel):

Model: 數(shù)據(jù)層,不包含邏輯

View:與用戶直接交互,只需處理觸發(fā)事件后的轉發(fā),和告訴他如何顯示

ViewModel:跟蹤view的事件,處理model層傳遞的數(shù)據(jù);公開方法、屬性,讓view保持最新的狀態(tài)

ios開發(fā)的設計模式有哪些

iOS開發(fā)就是為裝有iOS系統(tǒng)的設備完成應用軟件或游戲軟件的開發(fā),ios開發(fā)的設計模式有代理模式、觀察者模式、MVC模式、單例模式、策略模式和工廠模式。

iOS 設計模式(五)-KVO 詳解

KVO 的全稱是 Key-Value Observing,俗稱“鍵值觀察/監(jiān)聽”,是蘋果提供的一套事件通知機制,允許一個對象觀察/監(jiān)聽另一個對象指定屬性值的改變。當被觀察對象屬性值發(fā)生改變時,會觸發(fā) KVO 的監(jiān)聽方法來通知觀察者。KVO 是在 MVC 應用程序中的各層之間進行通信的一種特別有用的技術。

KVO 和 NSNotification 都是 iOS 中觀察者模式的一種實現(xiàn)。

KVO 可以監(jiān)聽單個屬性的變化,也可以監(jiān)聽集合對象的變化。監(jiān)聽集合對象變化時,需要通過 KVC 的 mutableArrayValueForKey: 等可變代理方法獲得集合代理對象,并使用代理對象進行操作,當代理對象的內(nèi)部對象發(fā)生改變時,會觸發(fā) KVO 的監(jiān)聽方法。集合對象包含 NSArray 和 NSSet 。

先創(chuàng)建一個類,作為要監(jiān)聽的對象。

監(jiān)聽實現(xiàn)

KVO 主要用來做鍵值觀察操作,想要一個值發(fā)生改變后通知另一個對象,則用 KVO 實現(xiàn)最為合適。斯坦福大學的 iOS 教程中有一個很經(jīng)典的案例,通過 KVO 在 Model 和 Controller 之間進行通信。如圖所示:

KVO 觸發(fā)分為自動觸發(fā)和手動觸發(fā)兩種方式。

如果是監(jiān)聽對象特定屬性值的改變,通過以下方式改變屬性值會觸發(fā) KVO:

如果是監(jiān)聽集合對象的改變,需要通過 KVC 的 mutableArrayValueForKey: 等方法獲得代理對象,并使用代理對象進行操作,當代理對象的內(nèi)部對象發(fā)生改變時,會觸發(fā) KVO。集合對象包含 NSArray 和 NSSet 。

普通對象屬性或是成員變量使用:

NSArray 對象使用:

NSSet 對象使用:

observationInfo 屬性是 NSKeyValueObserving.h 文件中系統(tǒng)通過分類給 NSObject 添加的屬性,所以所有繼承于 NSObject 的對象都含有該屬性;

可以通過 observationInfo 屬性查看被觀察對象的全部觀察信息,包括 observer 、 keyPath 、 options 、 context 等。

注冊方法 addObserver:forKeyPath:options:context: 中的 context 可以傳入任意數(shù)據(jù),并且可以在監(jiān)聽方法中接收到這個數(shù)據(jù)。

context 作用:標簽-區(qū)分,可以更精確的確定被觀察對象屬性,用于繼承、 多監(jiān)聽;也可以用來傳值。

KVO 只有一個監(jiān)聽回調方法 observeValueForKeyPath:ofObject:change:context: ,我們通常情況下可以在注冊方法中指定 context 為 NULL ,并在監(jiān)聽方法中通過 object 和 keyPath 來判斷觸發(fā) KVO 的來源。

但是如果存在繼承的情況,比如現(xiàn)在有 Person 類和它的兩個子類 Teacher 類和 Student 類,person、teacher 和 student 實例對象都對象的 name 屬性進行觀察。問題:

當 name 發(fā)生改變時,應該由誰來處理呢?

如果都由 person 來處理,那么在 Person 類的監(jiān)聽方法中又該怎么判斷是自己的事務還是子類對象的事務呢?

這時候通過使用 context 就可以很好地解決這個問題,在注冊方法中為 context 設置一個獨一無二的值,然后在監(jiān)聽方法中對 context 值進行檢驗即可。

蘋果的推薦用法:用 context 來精確的確定被觀察對象屬性,使用唯一命名的靜態(tài)變量的地址作為 context 的值??梢詾檎麄€類設置一個 context ,然后在監(jiān)聽方法中通過 object 和 keyPath 來確定被觀察屬性,這樣存在繼承的情況就可以通過 context 來判斷;也可以為每個被觀察對象屬性設置不同的 context ,這樣使用 context 就可以精確的確定被觀察對象屬性。

context 優(yōu)點:嵌套少、性能高、更安全、擴展性強。

context 注意點:

KVO 可以監(jiān)聽單個屬性的變化,也可以監(jiān)聽集合對象的變化。監(jiān)聽集合對象變化時,需要通過 KVC 的 mutableArrayValueForKey: 等方法獲得代理對象,并使用代理對象進行操作,當代理對象的內(nèi)部對象發(fā)生改變時,會觸發(fā) KVO 的監(jiān)聽方法。集合對象包含 NSArray 和 NSSet 。(注意:如果直接對集合對象進行操作改變,不會觸發(fā) KVO。)

可以在被觀察對象的類中重寫 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key 方法來控制 KVO 的自動觸發(fā)。

如果我們只允許外界觀察 person 的 name 屬性,可以在 Person 類如下操作。這樣外界就只能觀察 name 屬性,即使外界注冊了對 person 對象其它屬性的監(jiān)聽,那么在屬性發(fā)生改變時也不會觸發(fā) KVO。

也可以實現(xiàn)遵循命名規(guī)則為 + (BOOL)automaticallyNotifiesObserversOfKey 的方法來單一控制屬性的 KVO 自動觸發(fā),Key 為屬性名(首字母大寫)。

使用場景:

使用 KVO 監(jiān)聽成員變量值的改變;

在某些需要控制監(jiān)聽過程的場景下。比如:為了盡量減少不必要的觸發(fā)通知操作,或者當多個更改同時具備的時候才調用屬性改變的監(jiān)聽方法。

由于 KVO 的本質,重寫 setter 方法來達到可以通知所有觀察者對象的目的,所以只有通過 setter 方法或 KVC 方法去修改屬性變量值的時候,才會觸發(fā) KVO,直接修改成員變量不會觸發(fā) KVO。

當我們要使用 KVO 監(jiān)聽成員變量值改變的時候,可以通過在為成員變量賦值的前后手動調用 willChangeValueForKey: 和 didChangeValueForKey: 兩個方法來手動觸發(fā) KVO,如:

NSKeyValueObservingOptionPrior (分別在值改變前后觸發(fā)方法,即一次修改有兩次觸發(fā))的兩次觸發(fā)分別在 willChangeValueForKey: 和 didChangeValueForKey: 的時候進行的。

如果注冊方法中 options 傳入 NSKeyValueObservingOptionPrior ,那么可以通過只調用 willChangeValueForKey: 來觸發(fā)改變前的那次 KVO,可以用于在屬性值即將更改前做一些操作。

有時候我們可能會有這樣的需求,KVO 監(jiān)聽的屬性值修改前后相等的時候,不觸發(fā) KVO 的監(jiān)聽方法,可以結合 KVO 的自動觸發(fā)控制和手動觸發(fā)來實現(xiàn)。

例如:對 person 對象的 name 屬性注冊了 KVO 監(jiān)聽,我們希望在對 name 屬性賦值時做一個判斷,如果新值和舊值相等,則不觸發(fā) KVO,可以在 Person 類中如下這樣實現(xiàn),將 name 屬性值改變的 KVO 觸發(fā)方式由自動觸發(fā)改為手動觸發(fā)。

有些情況下我們想手動觀察集合屬性,下面以觀察數(shù)組為例。

關鍵方法:

需要注意的是,根據(jù) KVC 的 NSMutableArray 搜索模式:

有些情況下,一個屬性的改變依賴于別的一個或多個屬性的改變,也就是說當別的屬性改了,這個屬性也會跟著改變。

比如我們想要對 Download 類中的 downloadProgress 屬性進行 KVO 監(jiān)聽,該屬性的改變依賴于 writtenData 和 totalData 屬性的改變。觀察者監(jiān)聽了 downloadProgress ,當 writtenData 和 totalData 屬性值改變時,觀察者也應該被通知。以下有兩種方法可以解決這個問題。

以上兩個方法可以同時存在,且都會調用,但是最終結果會以 keyPathsForValuesAffectingValueForKey: 為準。

以上方法在觀察集合屬性時就不管用了。例如,假如你有一個 Department 類,它有一個裝有 Employee 類的實例對象的數(shù)組,Employee 類有 salary 屬性。你希望 Department 類有一個 totalSalary 屬性來計算所有員工的薪水,也就是在這個關系中 Department 的 totalSalary 依賴于所有 Employee 實例對象的 salary 屬性。以下有兩種方法可以解決這個問題。

有時候我們難以避免多次注冊和移除相同的 KVO,或者移除了一個未注冊的觀察者,從而產(chǎn)生可能會導致 Crash 的風險。

三種解決方案: 黑科技防止多次添加刪除KVO出現(xiàn)的問題

我們在對象添加監(jiān)聽之前分別打印對象類型

我們看到,添加監(jiān)聽后,使用 object_getClass 方法獲取model類型時獲取到的是 NSKVONotifying_DJModel 。

這里就產(chǎn)生了幾個問題:

從打印結果可以看出, NSKVONotifying_DJModel 是 DJModel 的子類,說明我們添加了監(jiān)聽之后動態(tài)創(chuàng)建了一個 DJModel 的子類 NSKVONotifying_DJModel ,并將對象 DJModel 的類型更改為了 NSKVONotifying_DJModel 。

我們從源碼看出,實例對象調用 class 方法會返回 isa 指針,類對象調用 class 方法會返回自己,通過 object_getClass 方法獲取對象的類型也會返回 isa 指針。從源碼上看model對象添加監(jiān)聽之后使用 class 和使用 object_getClass 方法獲取到的類型應該是一樣的,但是這里卻不同,我們猜測在添加了監(jiān)聽之后在 NSKVONotifying_DJModel 中重寫了 class 方法。

我們打印一下添加監(jiān)聽前后 class 方法的 IMP 地址來確認是否重寫了 class 方法。

從打印結果可以看出,添加監(jiān)聽之后 class 方法的地址改變了,這驗證了我們之前的猜想, NSKVONotifying_DJModel 類中重寫了 class 方法。

我們監(jiān)聽對象時調用了 set 方法,我們對監(jiān)聽前后的 set 方法單獨分析。

我們再添加監(jiān)聽前后分別打印 setName 方法的 IMP 地址。

通過打印結果可以看出 setName 方法也在 NSKVONotifying_DJModel 中被重寫了,我們再使用lldb來看下 setName 具體是什么

第一個地址打印的是添加監(jiān)聽前 setName 方法的 IMP 地址,第二個打印的是添加監(jiān)聽后 setName 方法的 IMP 地址。

這里看出添加監(jiān)聽前 setName 對應的具體方法就是 setName ,但是添加監(jiān)聽后, setName 對應的雞頭方法卻變成了 _NSSetObjectValueAndNotify 函數(shù)。

下面我們就來研究一下 _NSSetObjectValueAndNotify 函數(shù)。

從上面與KVO相關的方法中我們可以看出,每一種數(shù)據(jù)類型都對應了一個 setXXXValueAndNotify 函數(shù)。

不過這些函數(shù)的具體實現(xiàn)沒有公布,所以內(nèi)部構造這里還是不清楚。

但是我們知道,在調用 `setXXXValueAndNotify 函數(shù)的過程中會調用另外兩個方法。

測試后得出了以下幾個結論:

我們還可以利用這兩個方法手動觸發(fā) observeValueForKeyPath 方法:

所以我們判斷在 _NSSetObjectValueAndNotify 函數(shù)內(nèi)部,在調用原來的 set 方法之前插入了 willChangeValueForKey 方法,在調用原來的 set 方法之后插入了 didChangeValueForKey 方法,并根據(jù)初始化時的枚舉值決定調用 observeValueForKeyPath 的時機。

(1)添加監(jiān)聽時,會動態(tài)創(chuàng)建一個監(jiān)聽對象類型的子類,并將監(jiān)聽對象的 isa 指針指向新的子類。

(2)子類中重寫了 class 和監(jiān)聽屬性的 set 方法。

(3)重寫 class 方法是為了不將動態(tài)創(chuàng)建的類型暴露出來。

(4)重寫 set 方法是將 set 方法的具體實現(xiàn)替換成了與屬性類型相關的 __NSSetXXXValueAndNotify 函數(shù)。

(5)在 __NSSetXXXValueAndNotify 函數(shù)內(nèi)部在 set 方法前后分別插入了 willChangeValueForKey 和 didChangeValueForKey 這兩個方法。

(6)根據(jù)添加監(jiān)聽時的枚舉值決定調用 observeValueForKeyPath 的具體時機。

網(wǎng)頁標題:ios開發(fā)中的設計模式,ios開發(fā)中的設計模式在哪
當前鏈接:http://www.muchs.cn/article30/phjeso.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)動態(tài)網(wǎng)站、網(wǎng)站改版軟件開發(fā)、、搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設計公司