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 - 수집 유형 -
두 가지 방법을 사람의 배열을 수정
- 다음 직접 배열을 제거하고 재 할당
- KVC는 해당 값을 수정 mutableArray와 배열로 설정.
- 세 흔히 사용되는 프로토콜은 각각의 방법은, 키 및 키 변수 경로가 프록시 에이전트 개체 액세스 방법을 정의한다 :
mutableArrayValueForKey:
그리고mutableArrayValueForKeyPath:
처럼 동작을 반환NSMutableArray
프록시 객체 객체입니다.mutableSetValueForKey:
그리고mutableSetValueForKeyPath:
처럼 동작을 반환NSMutableSet
프록시 객체 객체입니다.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);
- 주석 멤버 변수, 메소드는 의견의 집합을 제거한 다음 뷰를 실행합니다. 그러던 어느 방법으로 하나의 호출 순서의 의견 모습을 볼 수 있습니다
- 마찬가지로 멤버 변수 하나 하나 주석으로 살펴 취 [사람의 setValue를 @ "LG_Cooci"forKey는 @ "이름"] 순서의 멤버 변수에 할당
- 여부가. 1, 결정 SET <키> 2, _set <열쇠> (밑줄 속성 해제). 3, SETIS을 <키> 모든 실행. 그렇지 않을 경우, 계속
- 어떠한 조건 1 (단순 액세스 방법)이 없으면
- accessInstanceVariablesDirectly (폐쇄 또는 개방 인스턴스 변수 할당)를 분석하는 것은 YES 반환 존재한다.
- 반환이 NO 인 경우, 오류를 지시한다 설정 방법에 시간이되지 않습니다,이 방법은보고되지 않습니다.
- 이 실시 예는 변수의 값에 직접 제공된다
- 분석. 1, " _ <키> "2 " _is는 <키> ."3 " <키>" 이나. 4 " 는 <키> "인스턴스 변수와 같은
- accessInstanceVariablesDirectly (폐쇄 또는 개방 인스턴스 변수 할당)를 분석하는 것은 YES 반환 존재한다.
(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);
//}
인증 값들의 동일한 세트. 검증 결과 :
- " GET <키> ", " <키> ", " 는 <키> "또는 "_ <키> "가있는 경우, 단계 다섯째로 이동
- 조건 (1)가있는 NSArray 판사의 경우는 시작되지 않는 경우
- 결정 NSSet 여부
- 비 수집 유형
- 발견되면, 직접 액세스 인스턴스 변수의 값과는 5 단계로 진행
- 분석 " _ <키> " " _is <키> ", " <키> "이나 " 는 <키> "인스턴스 변수 등을
- accessInstanceVariablesDirectly YES이 반환 여부를 결정
- 거래의 세부 사항
- 그 결과의 NSNumber 스칼라 유형, NSValue로 변환 객체와 반환에 의해 지원되지 않는 경우
- 값의 NSNumber 스칼라 타입을 지원하는 경우, 그 복귀의 NSNumber 예에 저장된다.
- 속성 값은 개체 포인터를 검색하는 경우, 바로 결과를 반환합니다.
- vlueForUnderfinedKey 오류
- 컬렉션의 종류도 운영 할 필요가
3 세트 사업자
당신이 목표와 호환되는 코딩 키 - 값 보낼 때 valueForKeyPath:
메시지를 설정 연산자는 키 경로에 포함 할 수있다. 집합 연산자에서 기호에 따라 키의 작은 부분들 중 하나 인 (@), 심볼 지정 getter
동작은 어떤 방식으로 처리 된 데이터의 데이터를 반환하기 전에 수행 될 수있다. 에 의해 NSObject
제공되는 valueForKeyPath:
디폴트의 구현이 동작을 달성하는 것입니다.
@avg.属性名
컬렉션의 속성 객체를 평균화.
NSNumber *transactionAverage = [self.transactions valueForKeyPath:@"@avg.amount"];
@count
컬렉션의 개체 수를 찾는.@max.属性名
컬렉션의 속성 객체의 최대 값을 선택.@min.属性名
속성에서 객체의 최소한의하십시오.@sum.属性名
속성의 컬렉션 객체를 찾아.@distinctUnionOfObjects.属性名
객체의 세트에 속성의 모든 값을 제거하고,이 값은 새로운 배열 반환에 저장됩니다. 이 작업의 중복 제거.@unionOfObjects.属性名
객체의 세트에 속성의 모든 값을 제거하고,이 값은 새로운 배열 반환에 저장됩니다. 이 작업은 무거운하지 않습니다.@distinctUnionOfArrays.属性名
중첩 세트 (중첩 세트의 콜렉션) 특성의 모든 객체의 값을 반환 새로운 배열을 제거한다. 이 작업의 중복 제거.@unionOfArrays.属性名
중첩 세트 (중첩 세트의 콜렉션) 특성의 모든 객체의 값을 반환 새로운 배열을 제거한다. 이 작업은 무거운하지 않습니다.@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;
}