2013-08-22 54 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]被設置時,該方法不會被調用。我怎樣才能使這是我的setters的默認行爲?

回答

5

確實有辦法做到這一點。您可以聲明相關屬性@dynamic,然後使用+resolveInstanceMethod:實際按需創建setter。你可以在sample code for iOS:PTL中找到這樣的例子。此示例演示如何自動使您的訪問器讀取和寫入字典(properties)而不是從ivars讀取和寫入。爲了使這項工作適合您,您可能需要始終在字典中存儲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()功能:

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

然後調用方負責將包裝:

obj.foo = RNNonNull(mystuff); 

如果這是不可能的,我可能會用手工重寫getter就NSNull轉換爲nil而不是使用運行時來做(它會是一個單行的方法)。我使用運行時的唯一原因是如果有一堆屬性,並且對象非常簡單(純粹是一個數據對象)。

+1

雖然有用,但我不認爲這實際上回答了關於-setValue:forKey:可重寫性的問題。 –

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'。完成所需行爲的唯一方法是爲相關對象的所有屬性設置自定義設置器。您可以實現這樣的方法,即沒有觀察者將「NSNull」視爲值,但這比基於KVO的解決方案的開銷要大得多。 – ianyh