KVCはどのように属性にアクセスしますか?KVOはどうやって実現しますか?

3448 ワード

KVCはどのように属性にアクセスしますか?
  • KVCはある程度の代替アクセス方法(アクセス方法)を提供していますが、アクセス方法はあくまでも良いものです.KVCを使って属性を訪問する時、その内部は実は多くの事をしました:
  • は、まず、有否、set、isなどのproperty属性に対応するアクセス方法を検索し、有れば、直接にこれらの方法を使用する.
  • もしないならば、引き続き探して、_ゲットsetなどの方法は、あれば使う.
  • 以上のアクセス方法が見つからない場合、インスタンス変数への直接アクセスを試みる.
  • このメンバー変数にもアクセスできない場合、以下の方法で異常を投げます.この二つの方法を提供したのは、valueFor UnidefinedKey:とsetValue:forUnidefinedKey:方法は、この属性にアクセスできないため、プログラムが崩れそうになる前に、書き直してください.
  • KVOは何ですか
  • Key-Value Obersverは、キーの値を観察します.それは観察者モードの一種の誘導体である.基本的な考え方は、対象の属性に対して観察を加え、その属性が変化すると自動的に観察者に通知することである.ここでの通知とは、観察者オブジェクトの実現をトリガするKVOのインターフェース方法である.KVOはmodelとviewの同期を解決する良い方法である.また、KVOの利点は、観察された属性値が変更されると自動的に通知が送信されることであり、これは通知センターがpost通知を必要とするよりも簡単である.
  • まずターゲットの属性に観察を追加します.
  •  - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
    
  • は、通知を受信するために以下の方法を実現するために、各パラメータの意味に注意する必要がある:
  •  - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context;
    
  • 最後に観察者を除去します.
  • - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
    
    KVOはどうやって実現しますか?
    あるクラスのオブジェクトが最初に観察されると、システムは実行期間において、そのクラスの派生クラスを動的に作成し、この派生クラスにおいて、基質の中で観察された属性のsetter方法を書き換えて、setter方法において、通知機構を持たせる.したがって、KVOが有効になるには、直接または間接的にsetter方法で属性にアクセスする必要があります(KVCのsetValueは間接的な方式です).直接メンバー変数KVOにアクセスするのは有効ではありません.
    派生クラスはまた、class方法を「騙す」外部転用者として書き直しました.それが最初のクラスです.そしてシステムは、このオブジェクトのisaポインタをこの新たに誕生した派生クラスに向けているので、このオブジェクトは、派生クラスのオブジェクトとなるので、そのオブジェクトに対してsetterの呼び出しは書き換えのsetterを呼び出し、キー通知機構をアクティブにする.また、派生クラスはまた、資源を解放するためにdealloc方法を書き換えた.改めてsetterの方法で何をしたのかをお知らせする仕組みがありますか?実はただsetterの方法で、属性の割り当ての前後にそれぞれ二つの方法を呼び出しました.
    - (void)willChangeValueForKey:(NSString *)key;
    - (void)didChangeValueForKey:(NSString *)key;
     - (void)didChangeValueForKey:(NSString *)key;   
    
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context;
    
    これがKVO実現の基本原理です.アクセス方法がなく、KVCのsetValueによって属性値が変更されると、同じように運転中にsetValue:forKeyメソッドでもデフォルトで上の2つの方法が呼び出されます.実際には、通知機構を有するように、手動で明示的にこの2つの方法を呼び出すこともできる.以下は例で検証します.
    #import "ViewController.h"
    
    @interface ViewController ()
    {
        NSString            *_testStr;
    }
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //  self   self   ,       testStr    
        [self addObserver:self forKeyPath:@"testStr" options:NSKeyValueObservingOptionNew context:nil];
    
        [self willChangeValueForKey:@"testStr"];
        _testStr = @"this is a test"; //           ,     、          ,        
        [self didChangeValueForKey:@"testStr"];
    }
    
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if(object == self && [keyPath isEqualToString:@"testStr"])
        {
            NSLog(@"----new:%@----",change[@"new"]);
        }else
        {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    
    
    - (void)dealloc
    {
        //      
        [self removeObserver:self forKeyPath:@"stuName"];
    }
    
    @end