2013-08-22 2 views
3

모든 속성의 값으로 NSNull을 설정할 가능성이있는 개체가 있는데 NSNull 값이 좋지 않은 코드로 작업하고 있습니다. 내 객체에서 setValue : forKey :를 이와 같이 재정의 할 수 있습니까?setValue : forKey :?를 재정의 할 수 있습니까?

-(void)setValue:(id)value forKey:(NSString *)key { 

    if ([value isEqual:[NSNull null]]) { 
     [super setValue:nil forKey:key]; 
    } else { 
     [super setValue:value forKey:key]; 
    } 
} 

object.property = [NSNull null]이 설정되면 메서드가 호출되지 않습니다. 어떻게하면 내 설정 자의 기본 동작으로 만들 수 있습니까?

답변

5

확실한 방법이 있습니다. 관련 속성 인 @dynamic을 선언 한 다음 +resolveInstanceMethod:을 사용하여 주문형 작성기를 실제로 만들 수 있습니다. sample code for iOS:PTL에서 이와 같은 예를 찾을 수 있습니다. 이 예제는 접근자를 ivars가 아닌 사전 (properties)으로 읽고 쓰도록 자동으로 설정하는 방법을 보여줍니다. 이 기능을 사용하려면 사전에 NSNull을 항상 저장하고 게터 (propertyIMP())를 무시하여 nil으로 변환해야합니다.

[[self properties] setValue:value forKey:key]; 

에 :

[[self properties] setValue:(value ?: [NSNull null]) forKey:key]; 

변경 : 그래서 당신이 변경 것

return [[self properties] valueForKey:NSStringFromSelector(_cmd)]; 

에 : 그런

id value = [[self properties] valueForKey:NSStringFromSelector(_cmd)]; 
return (value == [NSNull null] ? nil : value); 

또는 무언가를.

그러나 이것이 중요한 승리가 아니라면 나는 이런 종류의 마법을 피할 것입니다. 이것에 대한 나의 전형적인 해결책은 다른 방향으로 가야하고 발신자에게하지 말아야 할 때 [NSNull null]을 전달하지 않는 것입니다. 나는 RNNonNull() 같은 기능을 사용 : 그것은 가능하지 않으면

obj.foo = RNNonNull(mystuff); 

, 나는 아마 nilNSNull 변환 손으로 게터을 무시할 것 :

id RNNonNull(id x) { return (x == [NSNull null]) ? nil : x; } 

그런 다음 호출자는 래퍼를 추가하기위한 책임이있다 런타임 (그것을 한 줄 방법)과 함께하는 것보다. 런타임을 사용하는 유일한 이유는 여러 속성이 있고 개체가 매우 단순한 경우 (순수하게 데이터 개체) 때문입니다.

+1

유용하지만 실제로 이것이 -setValue : forKey : overridability와 관련된 질문에 응답하지 않았다고 생각합니다. –

2

속성을 설정해도 실제로는 setValue:forKey:가 호출되지 않습니다. KVO로이 작업을 수행 할 수 있습니다. 예를 들어,

@interface Foo 
@property (nonatomic, strong) NSObject *bar; 
@end 

@implementation 

- (id)init { 
    self = [super init]; 
    if (self) { 
     [self addObserver:self forKeyPath:@"bar" options:0 context:nil]; 
    } 
    return self; 
} 

- (void)dealloc { 
    [self removeObserver:self forKeyPath:@"bar"]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if (self.bar == [NSNull null]) { 
     self.bar = nil; 
    } 
} 

은 그래서 재산 bar[NSNull null로 설정되어 언제든지은 즉시 nil로 설정됩니다.

+0

NSNull과 nil 모두로 설정됩니다. 동일한 키 경로의 다른 관찰자는 여전히 'NSNull'을 볼 수 있습니다. – dreamlax

+0

그들은'[NSNull null]'과'nil'을 보게 될 것입니다. 원하는 동작을 수행하는 유일한 방법은 관련 개체의 모든 속성에 대한 사용자 지정 setter를 설정하는 것입니다. 관측자가 'NSNull'을 값으로 본 적이없는 방법을 구현할 수는 있지만 KVO 기반 솔루션보다 훨씬 오버 헤드가 큽니다. – ianyh

관련 문제