欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

ios開發(fā)常用的設(shè)計模式,ios設(shè)計原則

iOS 設(shè)計模式的應(yīng)用 ④ 單例模式

在數(shù)學(xué)和邏輯學(xué)中,單例定義為” 有且僅有一個元素的集合 “,在無論什么情況下,獲取到的都是同一個值。在程序中,單例模式保證一個類僅有一個實例,并提供一個訪問它的全局訪問點(diǎn)。這個方法應(yīng)該是類方法,阻止所有想要生成對象的訪問,避免一個全局使用的類頻繁地創(chuàng)建和銷毀。

創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計制作、網(wǎng)站設(shè)計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的港北網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

static uniqueInstance 是 Singleton 中的唯一實例, static sharedInstance 將它返回給客戶端。通常, shareInstance 會檢查 uniqueInstance 是否已經(jīng)被實例化,如果沒有,會生成一個實例然后返回 uniqueInstance 。

沒有接口,不能繼承,與單一職責(zé)原則沖突,一個類應(yīng)該只關(guān)心內(nèi)部邏輯,而不關(guān)心外面怎么樣來實例化。

只要應(yīng)用程序需要集中式的類來協(xié)調(diào)其服務(wù),這個類就應(yīng)該生成單一的實例,而不是多個實例。

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

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

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

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

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

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

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

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

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

如果是監(jiān)聽集合對象的改變,需要通過 KVC 的 mutableArrayValueForKey: 等方法獲得代理對象,并使用代理對象進(jìn)行操作,當(dāng)代理對象的內(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 作用:標(biāo)簽-區(qū)分,可以更精確的確定被觀察對象屬性,用于繼承、 多監(jiān)聽;也可以用來傳值。

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

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

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

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

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

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

context 優(yōu)點(diǎn):嵌套少、性能高、更安全、擴(kuò)展性強(qiáng)。

context 注意點(diǎn):

KVO 可以監(jiān)聽單個屬性的變化,也可以監(jiān)聽集合對象的變化。監(jiān)聽集合對象變化時,需要通過 KVC 的 mutableArrayValueForKey: 等方法獲得代理對象,并使用代理對象進(jìn)行操作,當(dāng)代理對象的內(nèi)部對象發(fā)生改變時,會觸發(fā) KVO 的監(jiān)聽方法。集合對象包含 NSArray 和 NSSet 。(注意:如果直接對集合對象進(jìn)行操作改變,不會觸發(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ā)通知操作,或者當(dāng)多個更改同時具備的時候才調(diào)用屬性改變的監(jiān)聽方法。

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

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

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

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

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

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

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

關(guān)鍵方法:

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

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

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

以上兩個方法可以同時存在,且都會調(diào)用,但是最終結(jié)果會以 keyPathsForValuesAffectingValueForKey: 為準(zhǔn)。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

測試后得出了以下幾個結(jié)論:

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

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

(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)替換成了與屬性類型相關(guān)的 __NSSetXXXValueAndNotify 函數(shù)。

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

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

iOS 設(shè)計模式(一)-代理模式

代理模式是一種消息傳遞方式,一個完整的代理模式包括:委托對象、代理對象和協(xié)議。

協(xié)議:用來指定代理雙方可以做什么,必須做什么。

委托對象:根據(jù)指定的協(xié)議,指定代理去完成什么功能。

代理對象:根據(jù)指定的協(xié)議,完成委托方需要實現(xiàn)的功能。

從上圖中可以看到三方之間的關(guān)系,在實際應(yīng)用中通過協(xié)議來規(guī)定代理雙方的行為,協(xié)議中的內(nèi)容一般都是方法列表,當(dāng)然也可以定義屬性。

協(xié)議是公共的定義,如果只是某個類使用,我們常做的就是寫在某個類中。如果是多個類都是用同一個協(xié)議,建議創(chuàng)建一個Protocol文件,在這個文件中定義協(xié)議。遵循的協(xié)議可以被繼承,例如我們常用的 UITableView ,由于繼承自 UIScrollView 的緣故,所以也將 UIScrollViewDelegate 繼承了過來,我們可以通過代理方法獲取 UITableView 偏移量等狀態(tài)參數(shù)。

協(xié)議只能定義公用的一套接口,類似于一個約束代理雙方的作用。但不能提供具體的實現(xiàn)方法,實現(xiàn)方法需要代理對象去實現(xiàn)。協(xié)議可以繼承其他協(xié)議,并且可以繼承多個協(xié)議,在iOS中對象是不支持多繼承的,而協(xié)議可以多繼承。

協(xié)議有兩個修飾符 @optional 和 @required ,創(chuàng)建一個協(xié)議如果沒有聲明,默認(rèn)是 @required 狀態(tài)的。這兩個修飾符只是約定代理是否強(qiáng)制需要遵守協(xié)議,如果 @required 狀態(tài)的方法代理沒有遵守,會報一個黃色的警告,只是起一個約束的作用,沒有其他功能。

無論是 @optional 還是 @required ,在委托方調(diào)用代理方法時都需要做一個判斷,判斷代理是否實現(xiàn)當(dāng)前方法,否則會導(dǎo)致崩潰。

在iOS中代理的本質(zhì)就是代理對象內(nèi)存的傳遞和操作,我們在委托類設(shè)置代理對象后,實際上只是用一個id類型的指針將代理對象進(jìn)行了一個弱引用。委托方讓代理方執(zhí)行操作,實際上是在委托類中向這個id類型指針指向的對象發(fā)送消息,而這個id類型指針指向的對象,就是代理對象。

通過上面這張圖我們發(fā)現(xiàn),其實委托方的代理屬性本質(zhì)上就是代理對象自身,設(shè)置委托代理就是代理屬性指針指向代理對象,相當(dāng)于代理對象只是在委托方中調(diào)用自己的方法,如果方法沒有實現(xiàn)就會導(dǎo)致崩潰。從崩潰的信息上來看,就可以看出來是代理方?jīng)]有實現(xiàn)協(xié)議中的方法導(dǎo)致的崩潰。

而協(xié)議只是一種語法,是聲明委托方中的代理屬性可以調(diào)用協(xié)議中聲明的方法,而協(xié)議中方法的實現(xiàn)還是有代理方完成,而協(xié)議方和委托方都不知道代理方有沒有完成,也不需要知道怎么完成。

由于代理對象使用強(qiáng)引用指針,引用創(chuàng)建的委托方對象,并且成為委托對象的代理。這就會導(dǎo)致委托對象的delegate屬性強(qiáng)引用代理對象,導(dǎo)致循環(huán)引用的問題,最終兩個對象都無法正常釋放。

我們將委托對象的delegate屬性,設(shè)置為弱引用屬性。

weak 和 assign 是一種“非擁有關(guān)系”的指針,通過這兩種修飾符修飾的指針變量,都不會改變被引用對象的引用計數(shù)。但是在一個對象被釋放后, weak 會自動將指針指向 nil ,而 assign 則不會。在iOS中,向 nil 發(fā)送消息時不會導(dǎo)致崩潰的,所以 assign 就會導(dǎo)致野指針的錯誤 unrecognized selector sent to instance 。

所以我們?nèi)绻揎棿韺傩裕€是用 weak 修飾,比較安全。

iOS常用設(shè)計模式

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

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

應(yīng)用場景:不同類之間的傳值與回調(diào)。

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

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

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

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

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

應(yīng)用場景:功能集中管理的模塊可以封裝為單例,方便外界調(diào)用。

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

MVC(Model View Controller):

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

view:視圖層,負(fù)責(zé)頁面展示

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

MVVM(model view viewModel):

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

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

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

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

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

網(wǎng)站欄目:ios開發(fā)常用的設(shè)計模式,ios設(shè)計原則
URL分享:http://chinadenli.net/article29/dssppch.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)用戶體驗App設(shè)計網(wǎng)站排名Google營銷型網(wǎng)站建設(shè)

廣告

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

微信小程序開發(fā)