[KVC翻訳]2.1-Key-Value Coding Programming Guide公式ドキュメント第2部

7531 ワード

Key-Value Coding Programming Guide公式ドキュメント第2部第1節2018.9.20第1回修正
iOS-KVC公式ドキュメント第2部第1節

Key-Value Coding Fundamatals--Accessing Object Properties


キー値エンコーディングベース--オブジェクトのプロパティにアクセス

オブジェクト属性へのアクセス


オブジェクトは、通常、インタフェース宣言でプロパティを指定します.これらのプロパティは、次のカテゴリのいずれかに属します.
  • 属性.単純な値、たとえばスカラー(scalars)、文字列またはブール値を指します.値オブジェクト(例えばNSNumber)やその他の可変タイプ(例えばNSColor)も属性とみなされる.
  • 一対一の関係独自の属性を持つ可変オブジェクトを指します.オブジェクトのプロパティは、オブジェクト自体が変わらない場合に変更できます.たとえば、銀行口座オブジェクト(bank account object)には、addressプロパティを持つPersonオブジェクトのインスタンスであるownerプロパティがある場合があります.ownerのaddressは、銀行口座が保有するownerを変更することなく変更される可能性があります.銀行口座のownerは変更されていません.Personのaddressだけが変わった.
  • 一対多の関係.集合オブジェクトを指します.通常はNSArrayまたはNSSetこのようなコレクションのインスタンスを保存しますが、カスタムコレクションクラスを使用することもできます.

  • インベントリ2-1に宣言されたBankAccountオブジェクトは、各タイプの属性を示す.
    リスト2-1BankAccountオブジェクトの属性
    @interface BankAccount : NSObject
    
    @property (nonatomic) NSNumber* currentBalance;              // An attribute
    @property (nonatomic) Person* owner;                         // A to-one relation
    @property (nonatomic) NSArray* transactions;   // A to-many relation
    
    @end
    

    カプセル化を維持するために、オブジェクトは通常、インタフェースのプロパティにアクセスメソッドを提供します.オブジェクトの作成者は、これらの方法を明示的に記述したり、コンパイラに依存して自動的に合成したりすることができます.いずれにしても、これらのアクセサの1つを使用するコードの作成者は、コンパイルする前にプロパティ名をコードに書き込む必要があります.アクセサメソッドの名前は、そのコードを使用する静的部分となります.たとえば、インベントリ2-1に宣言されているBankAccountオブジェクトを指定すると、コンパイラはmyAccountインスタンスに対して呼び出すことができるsetterを合成します.
    [myAccount setCurrentBalance:@(100.0)];
    

    これは直接的ですが、柔軟性に欠けています.一方、キー値符号化に適合するオブジェクトは、文字列識別子を使用してオブジェクト属性にアクセスするより一般的なメカニズムを提供する.

    KeysとKeyPathsを使用してオブジェクトのプロパティを識別


    キー(key)は、特定の属性を識別する文字列です.通常、慣例に従って属性を表すキー(key)は、コードに表示される属性名である.キー(key)は、ASCIIコードを使用する必要があります.スペースは含まれず、通常は小文字で始まります(多くのクラスのURLプロパティなどの例外がありますが).
    リスト2-1のBankAccountクラスはキー値に適合して符号化されているため、キー(すなわちその属性の名称)ownercurrentBalance・およびtransactionsを識別することができる.呼び出しではなく、そのキーで値を設定することもできますsetCurrentBalance:メソッド:
    [myAccount setValue:@(100.0) forKey:@"currentBalance"];
    

    実際には、myAccountオブジェクトのすべてのプロパティを同じ方法で異なるキーパラメータで設定できます.パラメータは文字列タイプであるため、実行時に変数を操作できます.
    キーパスKey pathは、ポイントオペレータ.でキーを区切る文字列で、巡回するオブジェクト属性シーケンスを指定します.シーケンス内の最初のキーのプロパティは受信者に対して、各後続のキーは前のプロパティの値に対して計算されます.キーパス(Key path)は、単一のメソッドを使用してオブジェクトを深く呼び出す階層に役立ちます.
    例えば、銀行口座インスタンスに適用されるキーパスowner.address.streetは、銀行口座所有者アドレスに格納されている街文字列の値であり、仮定PersonおよびAddressクラスも一致するキー値符号化である.
    なお、Swiftでは、文字列を使用してキーまたはキーパスを示すのではなく、#keyPath式を使用できます.これは、Using Swift with Cocoa and Objective-C(Swift 4.2)のKeys and Key Paths章を参照して、コンパイル時のチェックの利点を提供します.

    キーを使用した属性値の取得


    オブジェクトは、NSKeyValueCodingプロトコルに従うときにキー値符号化に適合する.継承されたオブジェクト(NSObjectプロトコルの基本メソッドのデフォルト実装を提供)は、このプロトコルのデフォルト動作の一部を自動的に採用します.このようなオブジェクトは、少なくとも以下のキーベースの基本getterを実現します.
  • valueForKey:-keyパラメータで指定した属性の値を返します.アクセス者検索モードで記述されたルールに従ってkey名の属性が見つからない場合、オブジェクトは自身にvalueForUndefinedKey:メッセージを送信します.valueForUndefinedKey:発生したデフォルト実装放出NSUndefinedKeyException異常ですが、サブクラスはこの方法を上書きし、より優雅に処理できます.
  • valueForKeyPath:-受信機に対する指定キーパスの値を返します.keyPathシーケンスのいずれのオブジェクトも、特定のkeyのキー値符号化に合致しない-すなわち、デフォルト実装valueForKey:アクセスメソッドが見つからない--では、valueForUndefinedKey:メッセージが受信される.
  • dictionaryWithValuesForKeys:-受信機のキーのセットに対応する値を返します.この方法は配列内の各キー呼び出しvalueForKey:である.返されるNSDictionary配列内のすべてのキーの値を含む.

  • 注意集合オブジェクト(例えばNSArrayNSSetおよびNSDictionary)にはnilの値は含まれません.NSNullオブジェクトを使用してnil値を表します.NSNullは、オブジェクトのプロパティのnil値を表す単一のインスタンスを提供します.dictionaryWithValuesForKeys:のデフォルト実装と関連するsetValuesForKeysWithDictionary:NSNull(ディクショナリパラメータ内)とnil(格納された属性内)の間で自動変換されます.
    KeyPathを使用してプロパティをアドレッシングする場合、キーパスの最後のキーが1対のマルチリレーションシップ(すなわち参照セット)である場合、マルチペアのキーの右側には、キーのすべての値を含むセットが返されます.例えば、要求キーパス「transactions.payee」の値は、全てtransactionオブジェクトのうちpayeeオブジェクトを含む配列を返す.これは、KeyPathの複数の配列にも適用されます.KeyPathaccounts.transactions.payeeすべての勘定科目のすべての取引のすべての受取人オブジェクトを含む配列を返します.

    キーを使用した属性値の設定

    getterと同様に、キー値符号化に適合するオブジェクトにも共通setterのセットが設けられており、そのデフォルト動作は以下のNSKeyValueCodingプロトコルの実装NSObjectに基づいている.
  • setValue:forKey:-指定キーを所定値に設定します.setValue:forKey:のデフォルトインプリメンテーションでは、スカラーと構造体を表すNSNumberおよびNSValueオブジェクトに対して自動的に 操作を行い、対応する属性に設定します.パッケージ(warp)およびアンパッケージ(unwarp)の意味の詳細については、Representing Non-Object Valueを参照してください.

  • 受信setter呼び出したオブジェクトに指定キーに対応する属性がない場合、そのオブジェクトは自分に[setValue:forUndefinedKey:]メッセージを送信する.setValue:forUndefinedKey:のデフォルト実装が投げ出されるNSUndefinedKeyException異常.ただし、サブクラスは、このメソッドを書き換えてリクエストをカスタマイズして処理できます.
  • setValue:forKeyPath:受信者に対する指定キーパスに所定値を設定する.キーパスシーケンスで指定されたキーに対応するオブジェクトがキー値符号化互換性がない場合、setValue:forUndefinedKey:メッセージが受信されます.
  • setValuesForKeysWithDictionary:指定辞書の値を受信者の属性に設定し、辞書キーを使用して属性を識別する.デフォルト実装では、各キー値ペアを呼び出すsetValue:forKey:、必要に応じてnil置換NSNullオブジェクトを使用します.

  • デフォルトのインプリメンテーションでは、非オブジェクト属性をnil値に設定しようとすると、キー値符号化互換オブジェクトは、setNilValueForKey:メッセージを自分で送信します.setNilValueForKey:のデフォルトインプリメンテーションから放出される[NSInvalidArgumentException]例外ですが、オブジェクトはこのメソッドを書き換えてデフォルト値またはタグ値を置き換えることができます.詳細は、非オブジェクト値の処理を参照してください.

    キーを使用したオブジェクトアクセスのシンプル化


    keyベースgetterおよびsetterコードの簡略化方法については、次の例を参照してください.macOSでは、NSTableViewおよびNSOutlineViewオブジェクトの識別子文字列がそれぞれの列に関連付けられている.テーブルのモデル・オブジェクトがキー値符号化に合致しない場合、テーブルのデータ・ソース・メソッドは、リスト2-2に示すように、各カラム識別子を強制的にチェックし、返される正しい属性を順次検索します.また、将来的には、モデルに別の属性を追加する場合、この例ではPersonオブジェクトである、データソースメソッドに再アクセスし、新しい属性をテストして相関値を返す別の条件を追加する必要がある.
    インベントリ2-2キー値に基づいて符号化されないデータソース方法の実現
    - (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row {
        id result = nil;
        Person *person = [self.people objectAtIndex:row];
    
        if ([[column identifier] isEqualToString:@"name"]) {
            result = [person name];
        } else if ([[column identifier] isEqualToString:@"age"]) {
            result = @([person age]);  // Wrap age, a scalar, as an NSNumber
        } else if ([[column identifier] isEqualToString:@"favoriteColor"]) {
            result = [person favoriteColor];
        } // And so on...
    
        return result;
    }
    
    

    一方、リスト2−3は、キー値符号化互換性のあるPersonオブジェクトを用いた同じデータソースの方法のよりコンパクトな実装を示している.valueForKey:getterのみを使用し、データソースメソッドはカラム識別子をキーとして適切な値を返します.新しいカラムを後で追加するときに、カラム識別子が常にモデルオブジェクトのプロパティ名と一致する限り、カラム識別子は変わらないため、より短い時間に加えて一般的です.
    インベントリ2-3キー値符号化に基づくデータソース方法の実現
    - (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row {
        return [[self.people objectAtIndex:row] valueForKey:[column identifier]];
    }
    

    筆者のレベルが限られているため、文の中に間違いがあったり、もっと良い方法があったりしたら、大神さんに指摘してもらいたい.本文のすべてのdemoダウンロードリンクを添付し、【GitHub】.見終わったら役に立つと思ったら、GitHubでstarを注文してください.人にバラを贈り,手に余香がある.