티스토리 뷰
Key-Value Coding Programming Guide - Key-Value Coding Fundamentals - Accessor Search Patterns
rhinoPHS 2019. 2. 1. 23:28Key-Value Coding Programming Guide - Key-Value Coding Fundamentals - Accessor Search Patterns
NSObject에 있는 NSKeyValueCoding 프로토콜의 기본 구현은 명확하게 작성된 룰의 의해서 key-based accessor 호출을 객체의 기본 프로퍼티에 연결시킵니다. 이런 프로토콜 메소드들은 key 파라미터를 사용해서 접근자, 인스턴스 변수, 특정 네이밍 규칙을 따르는 관련 메소드에 대한 객체 인스턴스를 찾습니다. 이 기본 검색을 바꿀일은 거의 없지만 이해하면 KVC를 따르는 객체가 어떻게 동작하는지 알 수 있고 custom 객체에 KVC를 적용하는데 도움이 됩니다.
!Note
아래에 나오는 <key> or <Key> 는 KVC프로토콜 메서드에 사용되는 파라미터를 나타내는 key 문자열입니다.
이것은 보조 메서드(?)를 호출하거나 변수를 찾을 때도 사용됩니다. 매핑된 프로퍼티 이름은 <key>, <Key> case(대소문자형태)를 따릅니다. 예를 들어 <key>와 is<Key>인 경우 hidden이라는 프로퍼티는 hidden과 isHidden으로 매핑됩니다.
Search Pattern for the Basic Getter
key가 파라미터로 주워지는 valueForKey:는 기본적으로 다음과 같은 절차를 따릅니다.
1. get<Key>, <key>, is<Key>,_<key> 순으로 접근자를 찾고, 찾으면 그 메소드를 호출하고 결과값을 가지고 5단계를 진행하면됩니다. 그렇지 않으면 2번 부터 진행하면 됩니다.
2. 1에서 접근자를 못찾았다면, 인스턴스를 다음과 매치되는 메소드로 부터 찾는다. countOf<Key>: 그리고 objectIn<Key>AtIndex: ( 이 메소드들은 NSArray 클래스에 있는 원시 메소드와 대응 됩니다.) 그리고 <key>AtIndexes:(NSArray 메소드 objectsAtIndexes:에 대응)
countOf<Key>와 objectIn<Key>Index, <ket>Indexes중 하나를 찾게되면 콜렉션 프록시 객체가 만들어지고 반환된다. 이 프록시 객체는 NSArray처럼 작동한다. 못찾으면 3으로 간다.
이어서 프록시 객체는 수신한 모든 NSArray 메시지를 위에 3개의 메소드 메시지 그룹으로 변환한다. 그리고 이 메시지는 이 메소드를 가지고 있는 객체로 보내진다. 기존 객체가 get<Key>:range 옵셔널 메소드를 구현 했다면 그것 또한 적절한 때에 사용한다 .그리고 KVC compliant object와 같이 작동하는 proxy 객체는 NSArray처럼 작동합니다.
3. 접근자 메소드도 못 찾고 array 접근자 메소드 드룹도 못찾으면 NSSet 메소드에 해당하는 countOf<Key>, enumeratorOf<Key>, memberOf<Key>를 찾습니다. 그렇지 않으면 4로 갑니다.
프록시 객체는 수신된 모든 메시지를 위 3가지 메소드로 변환하고 객체에 보냅니다.
이 프록시 객체 또한 NSSet처럼 작동합니다.
4. 접근 메서드나 콜렉션 접근자 메소드 그룹에 없다면 accessInstanceVariablesDirectlry를 호출하고 YES를 리턴합니다. 그 _<key>, _is<Key>, <key>, is<KEy>으로 돼있는 인스턴스를 순서대로 찾습니다. 찾으면 값을 가지고 5번으로 가고 없다면 6번으로 갑니다.
5. 반환된 값이 객체 포인터이면 바로 리턴하고 스칼라 타입이면 NSNumber로 구조체타입이면 NSValue로 wrapping해서 리턴합니다.
6. 5번까지 실패했다면 valueForUndefinedKey를 호출하고 예외를 발생시킵니다. 앞서 말했듯이 이 메소드를 오버라이드해서 원하는 처리를 할 수도 있습니다 .
정리 : 접근자 -> array -> set, -> 인스턴스 변수
Search Pattern for the Basic Setter
setValue:forKey:는 기본적으로 key와 value가 파라미터로 주어지기 때문에 key에 해당하는 프로퍼티에 value를 넣어줍니다. ( 객체가 아닌 프로퍼티이면 value를 unwrap합니다.) 절차는 다음과 같습니다.
1. 먼저 set<Key>: or _set<Key> 순으로 접근자를 찾습니다. 찾으면 실행해서 값을 넣어주고(필요하면 unwrapp하고) 끝입니다.
2. 못 찾으면 accessInstanceVariablesDirectrly를 사용해서 YES를 리턴하고 _<key>, _is<Key>, <key>, is<KEy>으로 돼있는 인스턴스를 순서대로 찾습니다. 찾으면 value를 대입하고 끝입니다.
3. 접근자도 인스턴스 변수도 없으면 setValue:forUndefiendKey: 를 호출하고 예외를 발생시킵니다. 앞서 말했듯이 이 메소드를 오버라이드해서 원하는 처리를 할 수도 있습니다 .
Search Pattern for Mutable Arrays
mutableArrayValueForKey:는 기본적으로 input parameter로 key가 주어지기 때문에 키에 해당하는 변경가능한 프록시 array를 리턴합니다. 절차는 다음과 같습니다.
1. insertObject:in<Key>AtIndex:와 removeOjectFrom<Key>AtIndex:와 같이 쌍을 이루는 메소드를 찾습니다.(이 2 메소드는 NSMutableArray의 메소드인 insertObject:atIndex: and removeObjectAtIndex:에 대응합니다.) 또는 insert<Key>:atIndexes:와 remove<Key>Indexes:를 찾습니다. ( 이는 NSMutableArray insertObjects: atIndexes: and removeObjectsAtIndexes: 메소드 대응합니다.)
객체에 삽입과 제거 메소드 한 쌍이 하나라도 있으면 proxy object를 반환합니다. 이 객체는 NSMutableArray처럼 동작합니다. mutableArrayValueForKey: 함수의 원본 객체에 위에 나온 메소드을 가지고 메시지를 냅니다.
mutableArrayValueForKey:메시지를 받는 객체는 replaceObjectIn<Key>AtIndex:withObject나 replace<Key>AtIndexes:with<Key>를 구현할 수도 있습니다. 만약 구현을 하면 proxy객체가 그 메소드를 사용해서 퍼포먼스가 좋아 질 수 있습니다.
2. mutable array method가 없다면 없다면 set<Key>형태로된 접근자 메소드 를 찾습니다. 이 경우에는 mutableArrayValueForKey:의 원본 객체에게 set<key>메시지를 보내 NSMutableArray처럼 동작하는 프록시 객체를 반환합니다.
* 이 방법은 기존 컬렉션 객체를 수정하는 대신에 객체를 반복적으로 생성하기 때문에 비효율적입니다. 만약 custom으로 KVC을 따르는 객체를 만들 경우에는 피해야 합니다.
3. mutable array method도 없고 접근자 메소드도 없으면, accessInstanceVaribalesDirectly로 YES를 보내고 _<key> 나 <key> 를 순서대로 찾아 나갑니다.
인스턴스 변수가 있다면 프록시 객체를 리턴합니다. 이 객체는 NSMutableArray나 NSMutableArray의 하위 클래스처럼 동작합니다.
4. 다 실패하면 mutable collection proxy 객체를 리턴합니다. 이 객체는 setValue:forUndefinedKey: 메시지를 mutableArrayValueForKey:메시지의 원본 객체에게 보냅니다. 이 작업은 NSMutableArray 메시지를 받을 때마다 일어납니다.
setValue:forUndefinedKey는 NSUndefinedKeyexception에러를 기본으로 발생시키지면 오버라이드하면 원하는 동작을 하게 할 수 있습니다.
Search Pattern for the Mutable Ordered Sets
mutableOrderedSetValueForKey: 는 기본적으로 접근자 메소드와 orderedset접근자 메소드를 valueForKey와 동일한 생각합니다. 그리고 직접적으로 인스턴스 변수에 접하는 방법을 따르지만, 항상 변경 가능한 콜렉션 프로직 객체를 리턴합니다. 이와 더불어 아래 절차를 따릅니다.
1. insertObject:in<Key>AtIndex:와 removeOjectFrom<Key>AtIndex:를 찾습니다. 이는 NSMutableOrderedSet 클래스의 정의된 기본 메서드에 대응합니다.) 또한, insert<Key>:atIndexes:와 remove<Key>Indexes:를 찾습니다. ( 이는 NSMutableOrderedSet의 insertObjects: atIndexes: and removeObjectsAtIndexes: 메소드 대응합니다.)
삽입과 제거 메소드 한 쌍이 하나라도 있으면 proxy object를 반환합니다. 이 객체는 mutableOrderedSetValueForKey처럼 동작합니다. mutableArrayValueForKey: 함수의 원본 객체에 위에 나온 메소드을 가지고 메시지를 냅니다.
replaceObjectIn<Key>AtIndex:withObject나 replace<Key>AtIndexes:with<Key>를 구현할 수도 있습니다. 만약 구현을 하면 proxy객체가 그 메소드를 사용해서 퍼포먼스가 좋아 질 수 있습니다.
2. mutable set methods가 없으면 접근자 메소드(set<Key>:와 같은) 찾습니다;. 이경우 프록시 객체가 리턴되고, 리턴된 객체는 원본 객체에 set<Key>:를 보냅니다.
* 이 방법은 기존 컬렉션 객체를 수정하는 대신에 객체를 반복적으로 생성하기 때문에 비효율적입니다. 만약 custom으로 KVC을 따르는 객체를 만들 경우에는 피해야 합니다.
3. mutable set method도 없고 접근자 메소드도 없으면, accessInstanceVaribalesDirectly로 YES를 보내고 _<key> 나 <key> 를 순서대로 찾아 나갑니다.
인스턴스 변수가 있다면 프록시 객체를 리턴합니다. 이 객체는 NSMutableArray나 NSMutableArray의 하위 클래스처럼 동작합니다.
4. 다 실패하면 mutable collection proxy 객체를 리턴합니다. 이 객체는 setValue:forUndefinedKey: 메시지를 mutableArrayValueForKey:메시지의 원본 객체에게 보냅니다. 이 작업은 NSMutableArray 메시지를 받을 때마다 일어납니다.
setValue:forUndefinedKey는 NSUndefinedKeyexception에러를 기본으로 발생시키지면 오버라이드하면 원하는 동작을 하게 할 수 있습니다.
Search Pattern for Mutable Sets