なぜ必要なのですか?
おそらくご存知のように、多かれ少なかれわかりやすく深刻なアプリケーションの作成は、有能な設計なしにはできません。 最新のプログラミングの主なタスクの1つは、複雑さの制御、柔軟で拡張可能な可変アプリケーションを作成するための要件です。 これは、直交プログラミングの概念、クラス間の接続の最大削減、最適なアーキテクチャソリューションの使用(プロジェクトアーキテクチャを作成するための有能なアプローチ、クラス設計のアプローチ)を意味します。 すべての開発者が世界で経験した多くの工数と工数を経て、設計パターンと呼ばれる最も自然で成功したアプローチが開発されました...そして、クラス設計のアプローチは、使用されるプログラミング言語とオブジェクトの必要なプロパティに応じて、ある程度変更できます。 今日私が説明したパターンは、私のお気に入りの1つです(そして、一般的に非常に重要です)。 最後の2つの文に基づいて、この記事のタイトルが続きます。
オブザーバーパターンの最も完全で詳細な説明は、有名な本「Gangs of Four」- 「オブジェクト指向設計のテクニック 」で入手できます。 設計パターン
それでもパターンに関する良いチートシートがあります
すべてのパターンは3つのタイプに分けられます
-行動
-生成
-構造
オブザーバーは行動パターンです。
古典的な実装は次のとおりですが、通常どおり、標準実装からのいくつかの逸脱が可能です
この「オブザーバー」とは何ですか、利用可能な技術
オブザーバーを使用すると、プロジェクト内の依存関係の数を減らし、接続性を減らし、オブジェクトの相互依存性を減らし(あるオブジェクトの別のオブジェクトに関する知識、カプセル化の原理を減らします)、特定の問題グループを解決するアプローチを提供します。 現在のプロジェクトについて-次の問題がありました。
Navigation Controller階層に新しい注文(NewOrderViewController)を作成するためのView Controllerがあり、そこから他のビューへの遷移がありました(関税の選択、運送業者の選択、ルートの選択、注文日の選択、追加サービスの選択)。 以前、NewOrderViewControllerでviewWillAppearの注文価格の再計算を呼び出しましたが、これは最適なソリューションではありませんでした。ネットワーク要求を送信する必要があり、ユーザーはしばらくの間スタンバイインジケーターを見ることができたためです(たとえば)。 一般に、上記の注文パラメーターのいずれかを変更した後、注文価格を再計算する方が論理的です。 委任を使用(またはNewOrderViewControllerへの弱いリンクを保存)し、適切な場所で価格設定メソッドを呼び出すことができます。 しかし、このアプローチには複雑さや不便さが伴います。 より適切な方法が選択されました-モデルの変更を追跡するオブザーバーを作成するには、再計算メソッドであるPriceCalculatorクラスを呼び出します。再計算メソッドは、価格計算の結果/代行を使用して価格計算が開始された瞬間についてNewOrderViewControllerに通知しました。
次に、オブザーバーの構築方法について説明する必要があります。 この抽象化は、可能な限り自然で論理的な使いやすいものにする必要があります。
まず、監視技術のいずれかを独自に実装するか、既存の監視技術を使用する必要があります。
-(手動の場合)このようなテクノロジの設計は、監視する予定の対応するオブジェクトの変更を検出して、実行の独立したフローと実行ループ(サイクル)を作成することで実行できます。
-(既製のものを使用する場合)同様のタスクを満たすことができるiOS用の標準フレームワークには2つのソリューションしかありません
a)NSNotificationCenter(通知メカニズムを使用)
b)KVO(キー値監視)(クラスプロパティの変化の監視)
NSNotificationを使用したアプローチには重大な欠点があります。このため、必要なプロパティのセッターをオーバーロードし、
- postNotification:
を使用してNSNotificationを作成する必要があります
- postNotification:
- postNotification:
、およびいくつかの場所で明示的に示します
KVOの最も重要な利点は、観測されるクラスへの影響が最小限であり、観測可能性(観測オプション)を構成できる可能性、比較的単純であることです。
かなり重大な欠点もあります-パフォーマンスの深刻な消費(広範な使用の場合)ですが、私の場合、これに同意することにしました
したがって、選択はKVOに落ちました
キーバリュー監視
KVOに関する便利な記事:
公式文書(英語)、最も完全な
英語の2
3つのハブロフスカヤ
KVOを使用するには、キー値コーディングの基本原則も理解する必要があります。
KVOは、オブザーバーを追加および削除するためのメソッドを提供します
- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath; - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
そして、観測可能なプロパティの変更を記録する主な方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
プラスは、NSKeyValueObservingOptionsを選択する機能です
-NSKeyValueObservingOptionNew-NSDictionaryの新しい値を取得します(値が変更されたときに呼び出されます)
-NSKeyValueObservingOptionOld-NSDictionaryの古い値を取得します(変更前)
-NSKeyValueObservingOptionInitial-オブザーバーの予約直後に処理メソッドも機能する
-NSKeyValueObservingOptionPrior-ハンドラーは2回(変更前と変更後の両方)起動します(不明)
オプションは加算的で、ビット単位または
もう1つのプラスは、現在のオブジェクトだけでなく、ネストされたオブジェクト(結局、keyPath)のプロパティを追跡する機能です
現在の実装
残念なことに、コードリストをこすらなければなりませんでした!
当初は、オブザーバーを実装する基本クラスを作成するという考えでしたが、これは採算が取れないと判断されました。 したがって、すべてのオブザーバーはNSObjectsから継承されます。 オブザーバーは1対多の関係を実装する必要があるため、サブスクライバーメカニズムが考案されました。 変更を通知する必要がある各クラスは、オブザーバーにサブスクライブし、プロトコルから対応するメソッドを実装します。
各サブスクライバーはプロトコルをサポートする必要があります(AddressPathObserverの場合、これは
, OrderObserver - , :
/ , -
- ! , - , (- , - ), . , NSSet, . - . - , , - , , . , , , . - NSMapTable NSHashTable, . NSHashTable - NSSet, (weak) .
- , ( ) . ( - ). , , . , - , , . , :
KVO - - . , - .
/
. , - . , .
-, (, )
, . - ( ), , . , , . ;)
! , . , / - , , :
[self willChangeValueForKey:@"addressPath"]; [_addressPath addObject:newAddressPoint]; [self didChangeValueForKey:@"addressPath"];
, , ))
, OrderObserver - , :
/ , -
- ! , - , (- , - ), . , NSSet, . - . - , , - , , . , , , . - NSMapTable NSHashTable, . NSHashTable - NSSet, (weak) .
- , ( ) . ( - ). , , . , - , , . , :
KVO - - . , - .
/
. , - . , .
-, (, )
, . - ( ), , . , , . ;)
! , . , / - , , :
[self willChangeValueForKey:@"addressPath"]; [_addressPath addObject:newAddressPoint]; [self didChangeValueForKey:@"addressPath"];
, , ))