English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
iOSでのKVC、KVO、NSNotification、デリゲートの要約および違い
1KVC、NSKeyValueCoding という非公式のプロトコルで、オブジェクトの属性への間接的なアクセスメカニズムを提供します。setterやgetterメソッドを呼び出すのではなくアクセスします。KVOはKVCをベースにした鍵技術の1つです。
デモ:
@interface myPerson : NSObject { NSString*_name; int _age; int _height; int _weight; } @end @interface testViewController :UIViewController @property (nonatomic, retain) myPerson*testPerson; @end - (void)testKVC { testPerson = [[myPerson alloc] init]; NSLog(@"testPerson’s init height =%@", [testPerson valueForKey:@"height"]); [testPerson setValue:[NSNumber numberWithInt:168] forKey:@"height"]; NSLog(@"testPerson’s height = %@", [testPerson valueForKey:@"height"]); }
第一段のコードは、myPersonクラスを定義しており、_height属性がありますが、getter/setterのアクセスメソッドは提供されていません。また、testViewControllerクラスにはmyPersonオブジェクトポインタがあります。
myPersonインスタンスが生成された後、通常はこのオブジェクトの_height属性にアクセスすることができませんが、KVCを通じてアクセスすることができます。コードはtestKVCという関数です。
実行後、出力される値は以下の通りです:
2015-3-13 11:16:21.970 test[408:c07] testPerson’s init height = 0
2015-3-13 11:16:21.971 test[408:c07] testPerson’s height = 168
これは実際に_height属性を読み書きしたことを示しています。
KVCの常用メソッド:
- (id)valueForKey:(NSString *)key; -(void)setValue:(id)value forKey:(NSString *)key;
valueForKeyメソッドは、キーの値に基づいてオブジェクトの属性を読み取ります。setValue:forKey:は、キーの値に基づいてオブジェクトの属性を書き込みます。
注意:
(1). キーの値は正確でなければなりません。スペルミスがあると例外が発生します
(2). キーの値が未定義の場合、valueForUndefinedKey:このメソッドが呼び出されます。自分でこのメソッドを書いた場合、キーの値が間違っているとここに呼び出されます
(3). キーが重複してネストされているため、keyPathという概念があります。keyPathは、.記号を使ってキーを一つずつ結びつけるもので、このパスに基づいてアクセスすることができます
(4). NSArray/NSSetなどはKVCをサポートしています
2KVOはKeyValue Observeの略で、中国語ではキーワルューオブザーバーです。これは典型的なオブザーバーモードであり、観察者がキーワルの変更を受け取ると通知されます。iOSにはNotificationのメカニズムがありますが、このメカニズムにはCenterが必要であり、比較してKVOはより簡潔で直接的です。
KVOの使用も非常に簡単で、単純に3ステップ。
1.観察する必要があるオブジェクトの属性にオブザーバーを追加するaddObserver:forKeyPath:options:context:
2.observeValueForKeyPath:ofObject:change:context:メソッドを実装します。このメソッドは、観察している属性が変更されたときに自動的に呼び出されます。
3.オブザーバーを解除するremoveObserver:forKeyPath:context:
デモ:
@interface myPerson : NSObject { NSString *_name; int _age; int _height; int _weight; } @end @interface testViewController : UIViewController @property (nonatomic, retain) myPerson *testPerson; - (IBAction)onBtnTest:(id)sender; @end - (void)testKVO { testPerson = [[myPerson alloc] init]; [testPerson addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew context:nil]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"height"]) { NSLog(@"高さが変更されました!新しい=%@", [change valueForKey:NSKeyValueChangeNewKey]); } else {}} [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } - (IBAction)onBtnTest:(id)sender { int h = [[testPerson valueForKey:@"height"] intValue]; [testPerson setValue:[NSNumber numberWithInt:h+1] forKey:@"height"]; NSLog(@"person height=%@", [testPerson valueForKey:@"height"]); } - (void)dealloc { [testPerson removeObserver:self forKeyPath:@"height" context:nil]; [super dealloc]; }
第一段のコードでは、myPersonクラスが宣言され、_height属性があります。testViewControllerにはtestPersonオブジェクトのポインタがあります。
testKVOメソッド内で、testPersonオブジェクトのheight属性のオブザーバーを登録しました。testPersonのheight属性が変更された場合に通知を受け取ります。このメソッドでは、NSKeyValueObservingOptionNewパラメータを指定して、新しい値をdictionaryに渡すように要求しました。
observeValueForKeyPath:ofObject:change:context:メソッドをオーバーライドしました。このメソッドのchangeパラメータには、適切な値が含まれています。
強調したいのは、KVOのカールバックが呼び出される必要があり、属性はKVCのメソッドで変更する必要があります。属性を変更するためには、クラスの他のメソッドを呼び出すと、このオブザーバーは通知を受けません。
3、NSNotificationの用法はこちらのURLに見てください:http://blog.csdn.net/eduora_meimei/article/details/44198909
区別:
delegate の利点 :
1.非常に厳格な文法です。イベントをリスンするすべてのイベントは、delegate プロトコルで明確に定義されている必要があります。
2.もし delegate の中のメソッドが実装されていない場合、コンパイル警告が発生します。/エラー
3.プロトコルはcontrollerの範囲内で定義する必要があります
4.アプリケーション全体の制御プロセスは追跡可能で認識可能です;
5.あるcontrollerには、異なるdelegatesを持つ複数の異なるプロトコルを定義できます
6.サードパーティのオブジェクトを保持する必要はありません/通信プロセスを監視します。
7.呼び出されたプロトコルメソッドの返値を受け取ることができます。これは、delegateがcontrollerにフィードバック情報を提供できることを意味します
欠点 :
1.多くのコードを定義する必要があります:1.プロトコルの定義;2.controllerのdelegate属性;3.delegate自体でdelegateメソッドを定義します
2.代理オブジェクトを解放する際には、 delegateを慎重にnilに設定する必要があります。設定が失敗すると、解放オブジェクトのメソッドが呼ばれるとメモリクラッシュが発生します
3.あるcontrollerには複数のdelegateオブジェクトがあり、delegateが同じプロトコルを守っている場合でも、複数のオブジェクトに同じイベントを伝えることは難しいですが、可能です。
notificationの 优势 :
1.コードの量が少なく、実現が簡単;
2.発行された通知に対して、複数のオブジェクトが反応できます、すなわち、1多の方法で実現が簡単
3.controllerはcontextオブジェクト(dictionary)を渡すことができます。contextオブジェクトは、通知を送信する際のカスタム情報を持ちます
欠点 :
1.コンパイル時には、通知が観察者が正しく処理できるかどうかをチェックしません;
2.通知センターから登録されたオブジェクトを解放する際には、通知センターから登録を解除する必要があります;
3.デバッグ中に適用される作業および制御プロセスは追跡が難しいです;
4.controllerと観察者オブジェクトの関係を管理するためにサードパーティのツールが必要です;
5.controllerと観察者は事前に通知名、UserInfodictionaryのキーを知らなければなりません。これらが作業領域で定義されていない場合、同期が失敗します;
6.通知が発行された後、controllerは観察者から何もフィードバック情報を受け取れません。
KVOの 优势 :
1.オブジェクト間の同期を実現する簡単な方法を提供できます。例えば:modelとviewの間の同期;
2.内部オブジェクト(SKDオブジェクト)の実装を変更せずに、非私が作成したオブジェクトの状態変更に対応できます;
3.観察の属性の最新値および前の値を提供できます;
4.属性を観察するためにkey pathsを使用するため、ネストされたオブジェクトも観察できます;
5.観察オブジェクトの抽象化が完了しました。観察値が観察できるようにするために追加のコードは必要ありません
欠点 :
1.観察する属性はstringsを使用して定義する必要があります。そのため、コンパイラでは警告やチェックが発生しません;
2.属性のリファクタリングは、私たちの観察コードが利用できなくなることを意味します;
3.複雑な「IF」文は、オブジェクトが複数の値を監視している場合が必要です。これは、すべての観察コードが一つのメソッドを通じて指し示されるためです;
4.オブザーバーを解放する際には、オブザーバーを削除する必要はありません。
1.効率はもちろんで、delegateがNSNotificationよりも高いです。
delegateメソッドはnotificationよりも直接的です。最も典型的な特徴は、delegateメソッドはよく戻り値に注意を払います、つまりdelegateメソッドの結果です。例えば、-windowShouldClose:は、戻り値がyesかnoを気にする必要があります。したがって、delegateメソッドはよくshouldという言葉を含んでいます。つまり、あなたが私のdelegateを務める場合、私はあなたにウィンドウを閉じることに同意してくれますか?と尋ねます。あなたは答えを返してくれ、私はあなたの答えに基づいて次のステップを決めます。逆に、notificationの最大の特徴は、受信者の態度を気にしないことです。私は通知を出すだけで、あなたが受け取るかどうかはあなたのこと、結果も気にしません。したがって、notificationはdidという言葉がよく使われます。例えば、NSWindowDidResizeNotificationの場合、NSWindowオブジェクトがこのnotificationを出したら、何もしないし、受信者の反応を待たないです。
2、KVOとNSNotificationの違い:
delegateと同様に、KVOとNSNotificationの役割もクラス間の通信ですが、delegateとは異なります1)これらは通知を発行する責任がありますが、残りのことは気にしませんので、戻り値はありません;2)delegateは一对一だけですが、これらは一对多です。それぞれに特徴があります。
ご読覧ありがとうございます、皆様のサポートに感謝します!