키 값 코딩을 사용하여 개체에 대한 키가 존재하는지 어떻게 알 수 있습니까?
-
18-09-2019 - |
문제
객체에 iPhone SDK에 Writeable @Property가 있는지 테스트하고 싶습니다.
이 작업을 수행하는 한 가지 방법 중 하나는 -valueforkey : method를 확인하는 것이지만 다소 부적절 해 보입니다!
예시:
@try {
id *value = [instance valueForKey:@"myProperty"];
}
@catch (NSException * e) {
// Key did not exist
}
더 좋은 방법이 있습니까?
해결책
확인중인 객체를 만들면 재정의 할 수 있습니다. valueForUndefinedKey:
그리고 setValue:forUndefinedKey
예외를 제기하는 것보다 더 유용한 일을합니다.
반면에, 런타임에서 알지 못하는 객체를 내성적으로 지정하려고한다면 런타임 메소드를 사용하여이를 수행해야합니다. Objective-C 런타임 자체를 사용하고 class_copyPropertyList
또는 protocol_copyPropertyList
그리고 그것들을 다루거나 기초를 사용하고 전화하십시오. respondsToSelector
주어진 속성에 대한 KVC getter/setters의 개체, 예를 들어, 재산에 대한 foo
당신은 같은 것을 부를 것입니다 [someObject respondsToSelector:NSSelectorFromString(@"foo")];
.
다른 팁
일반적으로 객체에 주어진 키에 대한 값이 있는지 확인할 방법은 없습니다. 인스턴스는 그 정의되지 않은 키에 대한 값을 반환하기로 결정할 수 있습니다. -valueForUndefinedKey:
방법. 또는 기본 구현에 예외가 발생할 수 있습니다. 현대 대상 C (2.0) 객체 자주 공개 API의 관련 속성을 선언하십시오. 이러한 개체의 경우 Objective-C 런타임을 사용할 수 있습니다. class_copyPropertyList
또는 protocol_copyPropertyList
사용 가능한 속성 목록을 얻으려면 또한 KVC 검색 목록을 모방 할 수도 있습니다. repondsToSelector:
인스턴스가 적절한 getter 메소드에 응답하는 경우 마지막으로 런타임을 사용할 수 있습니다 class_copyIvarList
적절한 IVAR이 Ivars를 점검하려면. 이것은 많은 당신이 일하는 일 하지 말아야합니다. 객체 인스턴스가 보낸시 예외가 발생하는지 여부를 알지 못하는 것은 아닙니다. valueForKey:
메시지와 그것은 더 큰 문제를 나타냅니다 ...
주어진 키에 대한 값을 모두 제공 해야하는 객체 모음이 있지만 일부는 그렇지 않으면 디자인 문제가 있습니다. 적절한 인터페이스를 정의해야합니다 (a @protocol
대상 c)에서 필요한 속성을 선언합니다. 그런 다음이 프로토콜을 준수하거나 컴파일러를 사용하여 인스턴스가 프로토콜을 준수하는 경우 (단일 인스턴스를 전달하는 경우) 컴파일 타임 유형 확인을 수행 할 수 있습니다.
@Jason Coco 답변에서 다음.
다음은 설정하려는 속성의 "Set"Selectors가 있는지 특별히 확인하는 방법에 대한 제 제안입니다.
이것은 순수한 오물이지만 효과가 있고 나는 그것을 사용하는 것을 발견했습니다. 당신은 경고를 받았습니다 ..
NS_INLINE SEL _Nonnull IBPropertySetSelectorForPropertyName(NSString*_Nonnull propertyName)
{
NSString* firstLetter = [propertyName substringToIndex:1];
propertyName = [propertyName substringFromIndex:1];
propertyName = [[NSString alloc] initWithFormat:@"set%@%@:",firstLetter.capitalizedString,propertyName];
return NSSelectorFromString(propertyName);
}
용법:
Swift에서 : 브리징 헤더에 코드 스 니펫을 추가 한 다음 :
let key = "someKey"
let sel = IBPropertySetSelectorForPropertyName(key)
if SOMETHING.responds(to: sel) {SOMETHING.setValue(value, forKeyPath: key)}