KVC의 원리 실현

14295 단어

KVC란?


공식 문서:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/index.html#//apple_ref/doc/uid/10000107i
KVC(Key-Value Coding)는 Objective-C가 제공하는 문자열을 이용하여 대상 속성에 간접적으로 접근하는 메커니즘으로 액세서리를 통해 대상 속성에 접근하는 또 다른 선택할 수 있는 방안이다.비공식 프로토콜인 NSKeyValueCoding은 인터페이스를 정의했고 NSObject에서 인터페이스의 기본 구현을 제공했다.

2. 흔한 방법


// 
- (nullable id)valueForKey:(NSString *)key;

- (nullable id)valueForKeyPath:(NSString *)keyPath;

- (nullable id)valueForUndefinedKey:(NSString *)key;

// 
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;

- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);

- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;

- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;

- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);

- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;

// 
- (void)setValue:(nullable id)value forKey:(NSString *)key;

- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

- (void)setNilValueForKey:(NSString *)key;


3. KVC 원리


헤더 파일 찾기 NSKeyValueCoding.h 주석은 KVC의 실행 과정을 발견할 수 있습니다
  • valueForKey: (valueForKeyPath: 유사)
  • 먼저, 대상 클래스에서 순서대로 액세스 장치 이름이 -get, -, -is인 방법은 찾으면 직접 호출하고 방법이 되돌아오는 결과 형식이 바늘 형식이면 직접 되돌아온다.메소드 반환 결과 유형이 수량 유형이 NSNumber 변환을 지원하는 경우 NSNumber로 반환하고 그렇지 않으면 NSValue로 변환하여 반환합니다(임의의 유형의 결과가 NSValue로 변환되면 NSPoint, NSRect와 NSSize는 물론).
  • 그렇지 않으면(액세스 방법을 찾을 수 없음), -countOf, -indexInOfObject:, -objectInAtIndex:-AtIndexes:을 찾습니다.count 방법, index 방법과 다른 두 방법 중 최소한 한 방법을 찾으면 NSOrderedSet의 모든 방법에 응답할 수 있는 대리 집합 대상(NSKeyValueOrderedSet)을 되돌려줍니다.모든 NSOrderedSet 메시지가 에이전트 집합 대상에게 발송될 때, 메시지가 원시 수신기에 발송된 valueForKey:-countOf, -indexInOfObject:, -objectInAtIndex:-AtIndexes:의 조합으로 되돌아옵니다.선택할 수 있는 방법인 -get:range:을 실현하면 방법도 성능 최적화에 사용될 것이다.
  • 그렇지 않으면(액세스 방법과 NSOrderedSet 접근 방법을 찾을 수 없음) -countOf, -objectInAtIndex:-AtIndexes:을 찾으며,count 방법과 다른 두 방법 중 최소한 한 방법을 찾으면 NSArray의 모든 방법에 응답할 수 있는 프록시 집합 대상을 되돌려줍니다.모든 NSArray 메시지가 대리 집합 대상에게 발송될 때(NSKey Value Array), 메시지가 원시 수신기에 발송된 valueForKey:-countOf, -objectInAtIndex:-AtIndexes:의 조합으로 되돌아온다.선택할 수 있는 방법인 -get:range:을 실현하면 방법도 성능 최적화에 사용될 것이다.
  • 그렇지 않으면 (액세스 방법, NSOrderedSet 접근 방법,array 접근 방법을 찾을 수 없음) -countOf, -enumeratorOf, -memberOf:을 찾고, 세 가지 방법을 모두 찾으면 NSSet의 모든 방법에 응답할 수 있는 에이전트 집합 대상 (NSKeyValueSet) 을 되돌려줍니다.각 NSSet 메시지가 프록시 컬렉션 객체에 전송되면 원래 수신기에 valueForKey: 메시지가 -countOf, -enumeratorOf-memberOf: 의 조합으로 반환됩니다.
  • 그렇지 않으면(액세스 방법과 집합 접근 방법을 찾을 수 없음) +accessInstanceVariables Directly 속성이 YES로 되돌아오면 이름 _< key >, _is< Key >, < key > 또는 is< Key >에 맞는 실례 변수를 순서대로 찾습니다.인스턴스 변수가 발견되면 인스턴스 변수의 값을 반환하고 NSNumber 및 NSValue 동기화를 급격히 변환합니다.
  • 그렇지 않으면(액세스 방법, 집합 접근 방법과 실례 변수를 찾을 수 없음) -valueForUndefinedKey:을 호출하여 결과를 되돌려줍니다.-valueForUndefinedKey:의 기본 구현은 NSUndefinedKeyException 이상을 던지는 것입니다. 그러나 이 방법을 덮어씁니다.

  • 참고: 컬렉션(NSArray, NSSet, NSOrderSet)의 경우 일반 객체처럼 프록시 객체로 돌아가려면 다음과 같은 방법이 필요합니다. NSArray
    NSSet
    NSOrderSet -countOf -countOf -countOf -enumeratorOf -indexInOfObject:
    One of -memberOf:
    One of -objectInAtIndex: -objectInAtIndex: -AtIndexes: -AtIndexes:
    Optional (performance)
    Optional (performance) -get:range: -get:range:
  • setValue: forKey: (setValue: forKeyPath: 유사)
  • 우선, 클래스 액세서리 찾기 방법 -set:.이 방법을 찾으면 매개변수 유형을 체크합니다.매개 변수 형식이 대상 포인터 형식이 아니지만 값이 nil이면 -setNilValueForKey: 방법을 사용합니다. -setNilValueForKey: 방법의 기본 구현은 NSInvalid Argument Exception 이상을 던지는 것입니다. 그러나 이 방법을 덮어쓸 수 있습니다.그렇지 않으면 방법 매개 변수 형식이 대상 포인터 형식이라면 이 방법을 직접 호출하여value를 매개 변수로 전송합니다.메소드 매개변수 유형이 다른 유형이면 NSNumber/NSValue의 역변환은 메소드 -valueFor이 호출될 때 수행됩니다.
  • 그렇지 않으면(액세스 방법이 없음) +accessInstanceVariables Directly 속성이 YES로 되돌아오면 이름에 맞는 _< key >, _is< Key >, < key > 또는 is< Key >의 실례 변수를 순서대로 찾습니다.실례 변수를 찾았고, 그 형식이 대상 바늘 형식이라면, 이전 값에 대해release 작업을 한 다음value에 대해retain 작업을 하고, 실제 변수에 값을 부여합니다.다른 유형의 경우 1단계에서 NSNumber/NSValue를 변환한 다음 값을 지정합니다.
  • 그렇지 않으면 (액세스 방법과 실례 변수가 없음) setValue:forUndefinedkey: 방법을 사용합니다. setValue:forUndefinedkey: 방법의 기본 구현은 NSUndefinedKeyException 이상을 던지는 것입니다. 그러나 이 방법을 덮어쓸 수 있습니다.

  • 가변 집합 -mutableArrayValueForKey:key -mutableOrderedSetValueForKey:key -mutableSetValueForKey:key 기본 액세스 방법은 -valueForKey:key과 같습니다.프록시 대상을 되돌릴 때 실현해야 할 방법은 다르다.
  • NSMutableArray/NSMutableOrderedSet
    NSMutableSet
    At least 1 insertion and 1 removal method
    * At least 1 addition and 1 removal method -insertObject:inAtIndex: -addObject: -removeObjectFromAtIndex: -removeObject: -insert:atIndexes: -add: -removeAtIndexes: -remove:
    Optional (performance) one of
    * Optional (performance) -replaceObjectInAtIndex:withObject: -intersect: -replaceAtIndexes:with: -set:

    4. 실례


    1. YKNoteKVCObject 클래스 만들기

    //
    //  YKNoteKVCObject.h
    //  YKNote
    //
    //  Created by wanyakun on 2016/11/10.
    //  Copyright © 2016  com.ucaiyuan. All rights reserved.
    //
    
    #import 
    
    @interface YKNoteKVCObject : NSObject {
        NSInteger _intVar;
        NSString *_strVar;
    }
    
    @property (nonatomic, assign) NSInteger intProperty;
    @property (nonatomic, copy) NSString *strProperty;
    
    @end
    
    //
    //  YKNoteKVCObject.m
    //  YKNote
    //
    //  Created by wanyakun on 2016/11/10.
    //  Copyright © 2016  com.ucaiyuan. All rights reserved.
    //
    
    #import "YKNoteKVCObject.h"
    
    
    @implementation YKNoteKVCObject
    
    @synthesize intProperty = _intProperty;
    @synthesize strProperty = _strProperty;
    
    #pragma mark - method for orderSet
    - (NSUInteger)countOfOrderSet {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return 5;
    }
    
    - (NSInteger)indexInOrderSetOfObject:(id)element {
        return 2;
    }
    
    - (id)objectInOrderSetAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return [NSString stringWithFormat:@"orderSet_%ld", index];
    }
    
    #pragma mark - method for array
    - (NSUInteger)countOfArray {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return 10;
    }
    
    - (id)objectInArrayAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return [NSString stringWithFormat:@"array_%ld", index];
    }
    
    #pragma mark - mehtod for set
    - (NSUInteger)countOfSet {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return 15;
    }
    
    - (NSEnumerator *)enumeratorOfSet {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        NSEnumerator *enumerator = [[NSEnumerator alloc] init];
        return enumerator;
    }
    
    - (NSString *)memberOfSet:(NSString *)object {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        return [NSString stringWithFormat:@"member of set: %@", object];
    }
    
    #pragma mark - method for MutableOrderedSet
    - (void)insertObject:(NSString *)object inMOrderSetAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    - (void)removeObjectFromMOrderSetAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    #pragma mark - method for MutableArray
    - (void)insertObject:(NSString *)object inMArrayAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    - (void)removeObjectFromMArrayAtIndex:(NSUInteger)index {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    #pragma mark - method for mutableSet
    - (void)addMSetObject:(NSString *)object {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    - (void)removeMSetObject:(NSString *)object {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    }
    
    #pragma mark - private method
    - (id)valueForUndefinedKey:(NSString *)key {
        NSLog(@"%s
    ValueForUndefinedKey:%@", __PRETTY_FUNCTION__, key); return @"undefinedKeyValue"; } - (void)setNilValueForKey:(NSString *)key { NSLog(@"%s
    NilValueKey:%@", __PRETTY_FUNCTION__, key); } - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"%s
    undefineKey:%@", __PRETTY_FUNCTION__, key); } + (BOOL)accessInstanceVariablesDirectly { return YES; } #pragma mark getter setter - (NSInteger)intProperty { NSLog(@"%s", __PRETTY_FUNCTION__); return _intProperty; } - (void)setIntProperty:(NSInteger)intProperty { NSLog(@"%s", __PRETTY_FUNCTION__); _intProperty = intProperty; } - (NSString *)strProperty { NSLog(@"%s", __PRETTY_FUNCTION__); return _strProperty; } - (void)setStrProperty:(NSString *)strProperty { NSLog(@"%s", __PRETTY_FUNCTION__); _strProperty = [strProperty copy]; } @end

    2. setValue:ForKey:와valueForKey:등을 호출할 Controller 만들기

    //
    //  YKNoteKVCViewController.m
    //  YKNote
    //
    //  Created by wanyakun on 2016/11/11.
    //  Copyright © 2016  com.ucaiyuan. All rights reserved.
    //
    
    #import "YKNoteKVCViewController.h"
    #import "YKNoteKVCObject.h"
    #import 
    
    @interface YKNoteKVCViewController ()
    
    @property (nonatomic, strong) YKNoteKVCObject *yKNoteKVCObject;
    
    @end
    
    @implementation YKNoteKVCViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.title = @"KVC";
        self.view.backgroundColor = [UIColor whiteColor];
        // 
        [self.yKNoteKVCObject setValue:[NSNumber numberWithInteger:10] forKey:@"intProperty"];
        NSInteger intProperty = [[self.yKNoteKVCObject valueForKey:@"intProperty"] integerValue];
        NSLog(@"intProperty = %ld", intProperty);
        
        [self.yKNoteKVCObject setValue:@"I am strProperty" forKey:@"strProperty"];
        NSString *strProperty = [self.yKNoteKVCObject valueForKey:@"strProperty"];
        NSLog(@"strProperty = %@", strProperty);
        
        // 
        [self.yKNoteKVCObject setValue:[NSNumber numberWithInteger:20] forKey:@"intVar"];
        NSInteger intVar = [[self.yKNoteKVCObject valueForKey:@"intVar"] integerValue];
        NSLog(@"intVar = %ld", intVar);
    
        [self.yKNoteKVCObject setValue:@"I am strVar" forKey:@"strVar"];
        NSString *strVar = [self.yKNoteKVCObject valueForKey:@"strVar"];
        NSLog(@"strVar = %@", strVar);
    
        //set undefineKey
        [self.yKNoteKVCObject setValue:@"undefine value" forKey:@"undefinedKey"];
    
        // Object pointer nil
        [self.yKNoteKVCObject setValue:nil forKey:@"intProperty"];
    
        //NSOrderSet, NSArray, NSSet 
        id orderSet = [self.yKNoteKVCObject valueForKey:@"orderSet"];
        id array = [self.yKNoteKVCObject valueForKey:@"array"];
        id set = [self.yKNoteKVCObject valueForKey:@"set"];
        NSLog(@"
    orderSet class:%@
    array class:%@
    set class:%@", object_getClass(orderSet), object_getClass(array), object_getClass(set)); //NSMutableOrderSet, NSMutableArray, NSMutableSet id mutableOrderSet = [self.yKNoteKVCObject mutableOrderedSetValueForKey:@"mOrderSet"]; id mutableArray = [self.yKNoteKVCObject mutableArrayValueForKey:@"mArray"]; id mutableSet = [self.yKNoteKVCObject mutableSetValueForKey:@"mSet"]; NSLog(@"
    mutableOrderSet class:%@
    mutableArray class:%@
    mutableSet class:%@", object_getClass(mutableOrderSet), object_getClass(mutableArray), object_getClass(mutableSet)); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ #pragma mark - getter - (YKNoteKVCObject *)yKNoteKVCObject { if (_yKNoteKVCObject == nil) { _yKNoteKVCObject = [[YKNoteKVCObject alloc] init]; } return _yKNoteKVCObject; } @end

    3. 결과 내보내기

    -[YKNoteKVCObject setIntProperty:]
    -[YKNoteKVCObject intProperty]
    intProperty = 10
    -[YKNoteKVCObject setStrProperty:]
    -[YKNoteKVCObject strProperty]
    strProperty = I am strProperty
    intVar = 20
    strVar = I am strVar
    -[YKNoteKVCObject setValue:forUndefinedKey:]
    undefineKey:undefinedKey
    -[YKNoteKVCObject setNilValueForKey:]
    NilValueKey:intProperty
    orderSet class:NSKeyValueOrderedSet
    array class:NSKeyValueArray
    set class:NSKeyValueSet
    mutableOrderSet class:NSKeyValueFastMutableOrderedSet2
    mutableArray class:NSKeyValueFastMutableArray2
    mutableSet class:NSKeyValueFastMutableSet2
    

    좋은 웹페이지 즐겨찾기