14, 아이폰 OS 하단 분석 - KVC

KVC

사과 문서

KVC 정의

KVC (부호화 키 값) 부호화 키 IO에서 수단의 발전에 직접 오브젝트에 액세스 현상 중요한 속성 이름에 의해 허용 될 수 있거나, 객체 속성에 할당된다. 명시 적으로 액세스 방법을 호출 할 필요없이. 이 동적으로 액세스 할 수 있으며 런타임에 개체의 속성을 수정합니다. 오히려 컴파일시에 이상이 결정되며,이 마술 아이폰 OS 개발 중 하나입니다. 고위 아이폰 OS 개발자 기술의 대부분은 KVC 기반 구현입니다.

도트 구문과 사실 매우 차이가있는 KVC 액세스 개체를 사용하는 방법 클래스 접근 구현에서, 두 사람은 어떤 조합이 될 수 있습니다. 그러나 클래스의 메소드에서 접근이 없을, 도트 구문을 사용할 수 없습니다, 다음이를 KVC 장점.

KVC는 NSObject의의 정의는 상속 NSObject의 모든 종류의, KVC를 사용할 수 있도록, 오브젝티브 C는 명시 적 NSKeyValueCoding에게 카테고리 이름이 구현 확장하는 것입니다 (일부 일반 스위프트 클래스와 구조는 지원되지 않습니다 KVC는, 아니 상속 NSObject의) 때문에, 다음은 가장 중요한 KVC 네 가지 방법입니다 :

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值

- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值

- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值

- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

카테고리 다른 방법을 NSKeyValueCoding :

+ (BOOL)accessInstanceVariablesDirectly;
//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索

- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供属性值正确性�验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。

- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。

- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一个方法一样,但这个方法是设值。

- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法时面给Value传nil,则会调用这个方法

- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
//输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。

확장 :

문법 과제의 공통 점은 하단에 할당을 달성하는 방법이다.

기본 문법에 할당 점은 실제로 세터입니다

를 통해 컴파일러

typedef struct {
    float x, y, z;
} ThreeFloats;

@interface LGPerson : NSObject{
   @public
   NSString *myName;
}

@property (nonatomic, copy)   NSString          *name;
@property (nonatomic, strong) NSArray           *array;
@property (nonatomic, strong) NSMutableArray    *mArray;
@property (nonatomic, assign) int age;
@property (nonatomic)         ThreeFloats       threeFloats;
@property (nonatomic, strong) LGStudent         *student;
    LGPerson *person = [[LGPerson alloc] init];
    // 一般setter 方法
    person.name      = @"LG_Cooci";
    person.age       = 18;
    person->myName   = @"cooci";
    NSLog(@"%@ - %d - %@",person.name,person.age,person->myName);

1 KVC 설정 처리

1, 키 - 값은 (KVC) 코딩 : 기본 유형

KVC 기본 세트, INT의 NSNumber 형식으로 켭니다. 다른 유형의 문서 마지막을 참조하십시오.

    [person setValue:@"KC" forKey:@"name"];
    [person setValue:@19 forKey:@"age"];
    [person setValue:@"酷C" forKey:@"myName"];
    NSLog(@"%@ - %@ - %@",[person valueForKey:@"name"],[person valueForKey:@"age"],[person valueForKey:@"myName"]);

2, KVC - 수집 유형 -

두 가지 방법을 사람의 배열을 수정

  1. 다음 직접 배열을 제거하고 재 할당
  2. KVC는 해당 값을 수정 mutableArray와 배열로 설정.
  3. 세 흔히 사용되는 프로토콜은 각각의 방법은, 키 및 키 변수 경로가 프록시 에이전트 개체 액세스 방법을 정의한다 :
    1. mutableArrayValueForKey:그리고  mutableArrayValueForKeyPath:처럼 동작을 반환 NSMutableArray프록시 객체 객체입니다.
    2. mutableSetValueForKey:그리고  mutableSetValueForKeyPath:     처럼 동작을 반환 NSMutableSet프록시 객체 객체입니다.
    3. mutableOrderedSetValueForKey:그리고  mutableOrderedSetValueForKeyPath:같은 행동을 돌아 NSMutableOrderedSet프록시 객체.
    person.array = @[@"1",@"2",@"3"];
    // 由于不是可变数组 - 无法做到
    // person.array[0] = @"100";
    NSArray *array = [person valueForKey:@"array"];
    // 用 array 的值创建一个新的数组
    array = @[@"100",@"2",@"3"];
    [person setValue:array forKey:@"array"];
    NSLog(@"%@",[person valueForKey:@"array"]);

    // KVC 的方式
    NSMutableArray *ma = [person mutableArrayValueForKey:@"array"];
    ma[0] = @"100";
    NSLog(@"%@",[person valueForKey:@"array"]);
    

3 KVC - 집합 연산자

[self dictionaryTest];
[self arrayMessagePass];
    //[self aggregationOperator];
    //[self arrayOperator];
    //[self arrayNesting];
    //[self setNesting];
    //[self arrayDemo];

#pragma mark - 字典操作

- (void)dictionaryTest{
    
    NSDictionary* dict = @{
                           @"name":@"Cooci",
                           @"nick":@"KC",
                           @"subject":@"iOS",
                           @"age":@18,
                           @"length":@180
                           };
    LGStudent *p = [[LGStudent alloc] init];
    // 字典转模型
    [p setValuesForKeysWithDictionary:dict];
    NSLog(@"%@",p);
    // 键数组转模型到字典
    NSArray *array = @[@"name",@"age"];
    NSDictionary *dic = [p dictionaryWithValuesForKeys:array];
    NSLog(@"%@",dic);
}

#pragma mark - KVC消息传递
- (void)arrayMessagePass{
    NSArray *array = @[@"Hank",@"Cooci",@"Kody",@"CC"];
    NSArray *lenStr= [array valueForKeyPath:@"length"];
    NSLog(@"%@",lenStr);// 消息从array传递给了string
    NSArray *lowStr= [array valueForKeyPath:@"lowercaseString"];
    NSLog(@"%@",lowStr);
}

4, KVC이 - 비 개체에 대한 액세스 속성 (중요)

비 객체 속성 액세스, 직접적으로 액세스 할 수 있습니다, 중간 형의 사용을 필요로한다. 즉 첫째 NSValue 형으로 변환 한 후 저장합니다. 또한 NSValue를받을 필요 읽을 때 다음 변환합니다.

    ThreeFloats floats = {1., 2., 3.};
    NSValue *value  = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
    [person setValue:value forKey:@"threeFloats"];
    NSValue *reslut = [person valueForKey:@"threeFloats"];
    NSLog(@"%@",reslut);
    
    ThreeFloats th;
    [reslut getValue:&th] ;
    NSLog(@"%f - %f - %f",th.x,th.y,th.z);

5 KVC - 액세스 층

학생의 속성 사람을 수정 한 후, 속성 stubent을 수정 한 다음 학생의 속성 사람에게 학생을 할당합니다.

@interface LGStudent : NSObject
@property (nonatomic, copy)   NSString          *name;
@property (nonatomic, copy)   NSString          *subject;
    LGStudent *student = [[LGStudent alloc] init];
    student.subject    = @"iOS";
    person.student     = student;
    [person setValue:@"测试" forKeyPath:@"student.subject"];
    NSLog(@"%@",[person valueForKeyPath:@"student.subject"]);

setValue의 : forKey : 

멤버 변수에 의해 분석. 때문에 공식 문서에보고하여 이유 멤버 변수가없는 속성 분석, 당신은 알 수와 세트 멤버 변수가 영향을 액세스 KVC는 멤버 변수는 하나의 변수의 원리를 가지고 있다는 요인, 속성은 자동으로 설정 방법을 발생한다. 분석을위한 멤버 변수에 따라서.

LGPerson.h
@interface LGPerson : NSObject{
    @public
    // NSString *_name;
    // NSString *_isName;
    // NSString *name;
    // NSString *isName;
}
LGPerson.m
//MARK: - setKey. 的流程分析
//- (void)setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}

//- (void)_setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}

//- (void)setIsName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}
// 1: KVC - 设置值的过程
    [person setValue:@"LG_Cooci" forKey:@"name"];

    NSLog(@"%@-%@-%@-%@",person->_name,person->_isName,person->name,person->isName);
//    NSLog(@"%@-%@-%@",person->_isName,person->name,person->isName);
//    NSLog(@"%@-%@",person->name,person->isName);
//    NSLog(@"%@",person->isName);
  1. 주석 멤버 변수, 메소드는 의견의 집합을 제거한 다음 뷰를 실행합니다. 그러던 어느 방법으로 하나의 호출 순서의 의견 모습을 볼 수 있습니다
  2. 마찬가지로 멤버 변수 하나 하나 주석으로 살펴 취 [사람의 setValue를 @ "LG_Cooci"forKey는 @ "이름"] 순서의 멤버 변수에 할당
    • 여부가. 1, 결정 SET <키> 2, _set <열쇠> (밑줄 속성 해제). 3, SETIS을 <키> 모든 실행. 그렇지 않을 경우, 계속
    • 어떠한 조건 1 (단순 액세스 방법)이 없으면
      • accessInstanceVariablesDirectly (폐쇄 또는 개방 인스턴스 변수 할당)를 분석하는 것은 YES 반환 존재한다.
        • 반환이 NO 인 경우, 오류를 지시한다 설정 방법에 시간이되지 않습니다,이 방법은보고되지 않습니다.
      • 이 실시 예는 변수의 값에 직접 제공된다
      • 분석. 1, " _ <키> "2 " _is는 <키> ."3 " <키>" 이나. 4 " 는 <키> "인스턴스 변수와 같은

(2) 공정의 값

// 2: KVC - 取值的过程
 person->_name = @"_name";
// person->_isName = @"_isName";
// person->name = @"name";
// person->isName = @"isName";

NSLog(@"取值:%@",[person valueForKey:@"name"]);
LGPerson.m
//MARK: - valueForKey 流程分析 - get<Key>, <key>, is<Key>, or _<key>,

//- (NSString *)getName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)name{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)isName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)_name{
//    return NSStringFromSelector(_cmd);
//}

인증 값들의 동일한 세트. 검증 결과 :

  1. " GET <키> ", " <키> ", " 는 <키> "또는 "_ <키> "가있는 경우, 단계 다섯째로 이동
  2. 조건 (1)가있는 NSArray 판사의 경우는 시작되지 않는 경우
  3. 결정 NSSet 여부
  4. 비 수집 유형
    1. 발견되면, 직접 액세스 인스턴스 변수의 값과는 5 단계로 진행
    2. 분석 " _ <키> " " _is <키> ", " <키> "이나 " 는 <키> "인스턴스 변수 등을
    3. accessInstanceVariablesDirectly YES이 반환 여부를 결정
  5. 거래의 세부 사항
    1. 그 결과의 NSNumber 스칼라 유형, NSValue로 변환 객체와 반환에 의해 지원되지 않는 경우
    2. 값의 NSNumber 스칼라 타입을 지원하는 경우, 그 복귀의 NSNumber 예에 저장된다.
    3. 속성 값은 개체 포인터를 검색하는 경우, 바로 결과를 반환합니다.
  6. vlueForUnderfinedKey 오류
  7. 컬렉션의 종류도 운영 할 필요가

3 세트 사업자

당신이 목표와 호환되는 코딩 키 - 값 보낼 때 valueForKeyPath:메시지를 설정 연산자는 키 경로에 포함 할 수있다. 집합 연산자에서 기호에 따라 키의 작은 부분들 중 하나 인 (@), 심볼 지정 getter동작은 어떤 방식으로 처리 된 데이터의 데이터를 반환하기 전에 수행 될 수있다. 에 의해 NSObject제공되는 valueForKeyPath:디폴트의 구현이 동작을 달성하는 것입니다.

  1. @avg.属性名  컬렉션의 속성 객체를 평균화.
NSNumber *transactionAverage = [self.transactions valueForKeyPath:@"@avg.amount"];
  1. @count      컬렉션의 개체 수를 찾는.
  2. @max.属性名  컬렉션의 속성 객체의 최대 값을 선택.
  3. @min.属性名  속성에서 객체의 최소한의하십시오.
  4. @sum.属性名  속성의 컬렉션 객체를 찾아.
  5. @distinctUnionOfObjects.属性名  객체의 세트에 속성의 모든 값을 제거하고,이 값은 새로운 배열 반환에 저장됩니다. 이 작업의 중복 제거.
  6. @unionOfObjects.属性名          객체의 세트에 속성의 모든 값을 제거하고,이 값은 새로운 배열 반환에 저장됩니다. 이 작업은 무거운하지 않습니다.
  7. @distinctUnionOfArrays.属性名   중첩 세트 (중첩 세트의 콜렉션) 특성의 모든 객체의 값을 반환 새로운 배열을 제거한다. 이 작업의 중복 제거.
  8. @unionOfArrays.属性名           중첩 세트 (중첩 세트의 콜렉션) 특성의 모든 객체의 값을 반환 새로운 배열을 제거한다. 이 작업은 무거운하지 않습니다.
  9. @distinctUnionOfSets.属性名     리턴 값은 인 NSSet효과와 distinctUnionOfArrays동일.
#pragma mark - 聚合操作符
// @avg、@count、@max、@min、@sum
- (void)aggregationOperator{
    NSMutableArray *personArray = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        LGStudent *p = [LGStudent new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"length":@(175 + 2*arc4random_uniform(6)),
                               };
        [p setValuesForKeysWithDictionary:dict];
        [personArray addObject:p];
    }
    NSLog(@"%@", [personArray valueForKey:@"length"]);
    
    /// 平均身高
    float avg = [[personArray valueForKeyPath:@"@avg.length"] floatValue];
    NSLog(@"%f", avg);
    
    int count = [[personArray valueForKeyPath:@"@count.length"] intValue];
    NSLog(@"%d", count);
    
    int sum = [[personArray valueForKeyPath:@"@sum.length"] intValue];
    NSLog(@"%d", sum);
    
    int max = [[personArray valueForKeyPath:@"@max.length"] intValue];
    NSLog(@"%d", max);
    
    int min = [[personArray valueForKeyPath:@"@min.length"] intValue];
    NSLog(@"%d", min);
}

 

4 형식 변환

하면 반환 값은 객체,이 값은 초기화하는 데 사용되는 게터가 아닌 경우 호출 게터 NSNumber제 (스칼라에 대한) 개체 또는 NSValue(구조) 개체를 값을 반환합니다.

마찬가지로, 기본적으로, 사용 setValue:forKey예 세터 : 특히, 속성 또는 인스턴스 변수를 액세스하기 위해 필요한 데이터의 종류를 결정하는 키를 지정. 데이터 형이 물체가없는 경우에는 제 1 설정은 적절한 <type> Value기초 자료를 추출 대상의 입력 값에 메시지를 전송하고, 그 데이터를 저장한다.

데이터 형식 작성 방법 접근 방법
BOOL numberWithBool: boolValue (in iOS) charValue (in macOS)*
char numberWithChar: charValue
double numberWithDouble: doubleValue
float numberWithFloat: floatValue
int numberWithInt: intValue
long numberWithLong: longValue
long long numberWithLongLong: longLongValue
short numberWithShort: shortValue
unsigned char numberWithUnsignedChar: unsignedChar
unsigned int numberWithUnsignedInt: unsignedInt
unsigned long numberWithUnsignedLong: unsignedLong
unsigned long long numberWithUnsignedLongLong: unsignedLongLong
unsigned short numberWithUnsignedShort: unsignedShort
데이터 형식 작성 방법 접근 방법
NSPoint valueWithPoint: pointValue
NSRange valueWithRange: rangeValue
NSRect valueWithRect: (맥 OS에만 해당). rectValue
NSSize valueWithSize: sizeValue

5, 사용자 정의 KVC

사용 NSObject의 형태 분류 NSKeyValueCoding 또한 디자인 패턴의 목적은 커플 링을 이해하는 것입니다 분류 NSObject의를 서면 찾을 수 있습니다. KVC 기능 NSObject의이 카테고리 내에서 작성.

그것은 서면으로 설명하지 않고, 사용자 정의 KVC는 달성하기 위해, 공식 문서에 따라 판단 단계적으로 실시한다.

6, KVC 팁

typedef struct {
    float x, y, z;
} ThreeFloats;

@interface LGPerson : NSObject{
    @public
    NSString *name;
    NSString *_name;
    NSString *_isName;
    NSString *isName;
    
}

@property (nonatomic, copy) NSString *subject;
@property (nonatomic, assign) int  age;
@property (nonatomic, assign) BOOL sex;
@property (nonatomic) ThreeFloats  threeFloats;

1,

// 1: KVC 自动转换类型
    NSLog(@"******1: KVC - int -> NSNumber - 结构体******");

    //age是int类型,需要转成NSNumber
    [person setValue:@18 forKey:@"age"];
    // 上面那个表达 大家应该都会! 但是下面这样操作可以?
    //由于age是int类型,即便是存的是用的字符串@“20”,KVC仍然能自动转换成NSCFNumber
    [person setValue:@"20" forKey:@"age"]; // int - string
    NSLog(@"%@-%@",[person valueForKey:@"age"],[[person valueForKey:@"age"] class]);//__NSCFNumber
    
    //由于sex是Bool类型,即便是存的是用的字符串@“20”,KVC仍然能自动转换成NSCFNumber
    [person setValue:@"20" forKey:@"sex"];
    NSLog(@"%@-%@",[person valueForKey:@"sex"],[[person valueForKey:@"sex"] class]);//__NSCFNumber

    //threeFloats式结构体类型,存的时候需要存NSValue类型
    ThreeFloats floats = {1., 2., 3.};
    NSValue *value  = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
    [person setValue:value forKey:@"threeFloats"];
    NSLog(@"%@-%@",[person valueForKey:@"threeFloats"],[[person valueForKey:@"threeFloats"] class]);//NSConcreteValue

 

 

// 2: 设置空值
    NSLog(@"******2: 设置空值******");
//设置age 会打印出“你傻不傻 。。。”,但是 subject 不会。是因为 setNilValueForKey 方法只能只对 NSNumber - NSValue的结构体进行处理,对NSString 不处理
    [person setValue:nil forKey:@"age"]; // subject不会走 - 官方注释里面说只对 NSNumber - NSValue
    [person setValue:nil forKey:@"subject"];
    
    // 3: 找不到的 key
    NSLog(@"******3: 找不到的 key******");
    [person setValue:nil forKey:@"KC"]; 

    // 4: 取值时 - 找不到 key
    NSLog(@"******4: 取值时 - 找不到 key******");
    NSLog(@"%@",[person valueForKey:@"KC"]);
    
    // 5: 键值验证
    NSLog(@"******5: 键值验证******");
    NSError *error;
    NSString *name = @"LG_Cooci";
    if (![person validateValue:&name forKey:@"names" error:&error]) {
        NSLog(@"%@",error);
    }else{
        NSLog(@"%@",[person valueForKey:@"name"]);
    }
person.m
//设置age 会打印出“你傻不傻 。。。”,但是 subject 不会。是因为 setNilValueForKey 方法只能只对 NSNumber - NSValue的结构体进行处理,对NSString 不处理
- (void)setNilValueForKey:(NSString *)key{
    NSLog(@"你傻不傻: 设置 %@ 是空值",key);
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"你瞎啊: %@ 没有这个key",key);
}

- (id)valueForUndefinedKey:(NSString *)key{
    NSLog(@"你瞎啊: %@ 没有这个key - 给你一个其他的吧,别奔溃了!",key);
    return @"Master 牛逼";
}

//MARK: - 键值验证 - 容错 - 派发 - 消息转发
//这里可以进行重定向,运行时进行容错,派发等
- (BOOL)validateValue:(inout id  _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError *__autoreleasing  _Nullable *)outError{
    if([inKey isEqualToString:@"name"]){
        [self setValue:[NSString stringWithFormat:@"里面修改一下: %@",*ioValue] forKey:inKey];
        return YES;
    }
    *outError = [[NSError alloc]initWithDomain:[NSString stringWithFormat:@"%@ 不是 %@ 的属性",inKey,self] code:10088 userInfo:nil];
    return NO;
}

 

 

 

 

 

 

 

게시 83 개 원래 기사 · 원의 찬양 (12) · 전망 180 000 +

추천

출처blog.csdn.net/shengdaVolleyball/article/details/104279749