티스토리 뷰

Key-Value Coding Programming Guide - Key-Value Coding Fundamentals - Accessing Object Properties

객체 인터페이스에 선언된 프로퍼티는 Attributes, To-one relationships, To-many relationships에 속한다.
Attributes : 간단한 값들... 스칼라, strings, Boolean 값과 NSNumber은 객체, NSColor같은 불변타입 등...
To-one relationships : 객체안에 객체 프로피터가 1:1관계
To-many relationships : collections 객체들

Listing 2-1Properties of the BankAccount object
  1. @interface BankAccount : NSObject
  2. @property (nonatomic) NSNumber* currentBalance; // An attribute
  3. @property (nonatomic) Person* owner; // A to-one relation
  4. @property (nonatomic) NSArray< Transaction* >* transactions; // A to-many relation
  5. @end
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/BasicPrinciples.html#//apple_ref/doc/uid/20002170-BAJEAIEE

캡슐화를 위해 객체는 프로퍼티 접근자를 만듭니다. 개발자가 명시적으로 적거나 synthesize를 이용해서 자동생성을 할수도 있습니다. 어떤 방법이던 개발자는 컴파일 하기 전에 프로터티이름은 적어야 합니다. 그래서 접근자 메소드는 그 메소드를을 사용하는 코드에 늘 있습니다. 위 예를 보면 모든 프로퍼티에 @property 예약어를 선언했기 때문에 아래와 같이 쓸 수 있습니다.

[myAccount setCurrentBalance:@(100.0)];


직접 접근할 수 있지만 유연하지 않고 고정돼 있습니다. 반면에 KVC를 사용하는 객체는 문자열(키)를 가지고 일반적인 접근 방법을 제공합니다. 


- Identifying an Object's Properties with Keys and Key Paths
여기서 key는 특정 프로퍼티를 식별하는 문자열입니다. 이 문자열은 객체에 선언된 프로퍼티 이름입니다. 이 key에는 ASCII인코딩만 사용합니다. 공백은 안되고 보통 소문자로 시작합니다. (URL주소는 예외입니다)

위 BankAccount는  NSObject를 상속받았기 때문에 자동으로 KVC를 따릅니다. 각 프로퍼티 네임(currentBalance, owner, transactions)을 키로 인식합니다. 바로 위 예제처럼 setCurrentBalance를 사용하지 않고 아래와 같이 사용합니다.

[myAccount setValue:@(100.0) forKey:@"currentBalance"];

다른 프로퍼티에도 똑같이 적용됩니다.

key path는 .(dot)으로 나눠지는 문자열로 객체간의 계층을 구조를 따라가는 경로입니다.
BankAccount 예제를 보면 owner.address.street 같이 할 수 있습니다. (owner 객체가 address프로퍼티를 가지고 있고, adress프로퍼티가 street프로퍼티를 가지고 있다고 가정, Person객체와 Address가 KVC를 따르고 있다고 가정)

!Note : 스위트트에서는 #keyPath 표현을 씁니다.

class Person: NSObject {

    @objc var someValue:Int

    

    init(someValue:Int) {

        self.someValue = someValue;

    }

}


let person = Person(someValue: 12)

person.value(forKey: #keyPath(Person.someValue))


그것 이외에도 Swift에서 NSObject를 상속받지 않고 아래와 같이 사용하는 표현도 있습니다.
위에 swift에서는 NSObject를 상속받아야 한다고 했는데 문서 최종 업데이트 이후(2016.10.27)에 새로운 게 생겼나 봅니다.

struct SomeStructure {

    var someValue: Int

}


let s = SomeStructure(someValue: 12)

let pathToProperty = \SomeStructure.someValue


let value = s[keyPath: pathToProperty]




- Getting Attribute Values Using Keysr
객체가 NSKeyValueCoding 프로토콜을 따르면 그 객체는 KVC 따른다고 할 수 있습니다.  그리고 NSObject를 상속받은 객체는 자동적으로 KVC를 자동적응로 따르게 되고, 프로토콜 필수 메소드의 기본구현을 사용할 수 있습니다. 기본 구현은 아래와 같습니다.

-valueForKey : 키에 해당하는 프로퍼티 값을 반환합니다. 뒤에나올 Accessor Search Patterns에 따라서 키를 찾아나가고 해당 하는 키가 없다면 valueForUndefinedKey:를 호출합니다. valueForUndefinedKey:는 기본적으로 NSUndefinedKeyException을 발생하지만 이 메서드르 오버라이드 하면 원하는 처리를 할 수 있습니다.

-valueForKeyPath: 는 키패스에 해당하는 프로퍼티 값을 반환합니다. KVC를 사용하지 않는 객체에 프로퍼티에 접근할 경우에는 valueForUndefinedKey를 호출합니다.

- dictionaryWithValuesForKeys: 여러 key들을 array로 묶어서 보내면 해당하는 값들 key와 묶어서 을 dic형태로 반환. 각각 키에대해 valueForKey를 호출합니다.

!Note
Collection objects는 nil 대신에 NSNull 객체를 사용합니다. dictionaryWithValuesForKeys:와 setValuesForKeysWithDictionary:는 각각 알아서 NSnull과 null을 unwrap과 wrap을 합니다.

key path에서 마지막 프로티가 일대다 관계일 때는 반환값은 NSArray, NSSet같은 collectiong 객체가 됩니다.

- Setting Attribute Values Using Keys
KVC를 사용하는 객체는 위에서 봤던 getter뿐만 아니라 여러 setter들을 제공합니다.

https://developer.apple.com/documentation/foundation/object_runtime/nskeyvaluecoding   여기 보시면 됩니다.


-setValue:forKey:는 해당 키에 해당하는 프로퍼티에 값을 넣습니다. 그리고 기본적으로 NSNumber와 NSValue는 unwrap합니다(스칼라값이나 구조체를 넣을 경우에는 개발자가 NSNumber, NSValue로 wrap해서 넣어야 합니다.). 키에 해당하는 프로퍼티가 없으면 setValue:forUndefiendKey: message.를 호출합니다. 이 메소드는 기본적으로 NSUndefinedKeyException을 호출합니다. 이 메서드를 오버라이드해서 원하는 동작을 할 수 도 있습니다.


- setValue:forKeyPath:

ket path에 해당하는 프로퍼티에 값을 넣습니다. 보통 객체간의 계층구조를 따라가는데, 그 과정에서 KVC를 사용하지 않는 객체가 있다면 setValue:forUndefinedKey:를 호출합니다.


- setValuesForKeysWithDictionary: 키값쌍을 dictionary로 만들어서 넣어줍니다. 기본적으로 각각의 키-값 쌍에 대해 setValue:forkey를 호출하고 필요에 따라서 NSNull 객체를 nil로 대체합니다.



기본 구현에서 non-object 프로퍼티에 nil을 넣으려고 하면 KVC를 사용하는 객체는 setNilValueForKey를 호출합니다. setNilValueForKey의 기본 구현은 NSInvalidArgumentException 에러를 발생시키지만 오버라이드하면 기본 값으로 대체하거나 하는 다른 처리를 할 수 있습니다. 


- Using Keys to Simplify Object Access
Listing 2-2Implementation of data source method without key-value coding
  1. - (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row
  2. {
  3. id result = nil;
  4. Person *person = [self.people objectAtIndex:row];
  5. if ([[column identifier] isEqualToString:@"name"]) {
  6. result = [person name];
  7. } else if ([[column identifier] isEqualToString:@"age"]) {
  8. result = @([person age]); // Wrap age, a scalar, as an NSNumber
  9. } else if ([[column identifier] isEqualToString:@"favoriteColor"]) {
  10. result = [person favoriteColor];
  11. } // And so on...
  12. return result;
  13. }


Listing 2-3Implementation of data source method with key-value coding

  1. - (id)tableView:(NSTableView *)tableview objectValueForTableColumn:(id)column row:(NSInteger)row
  2. {
  3. return [[self.people objectAtIndex:row] valueForKey:[column identifier]];
  4. }

if else 구문을 없애서 소스도 상당히 짧아졌습니다. 또한 컬럼이 추가 되더라도 소스 수정이 일어나지 않습니다. 물론 컬럼 식별자가 객제 모델의 property와 같아야 합니다.



반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함