我希望得到通知,當計數,即。 NSArray中的項目數目發生了變化.. 當然,如果我在控制添加和刪除對象到數組中,當然我不需要這個。但我不是,它在業務流程模型方面發生了不可預測的變化,並取決於外部因素。 有沒有一些簡單優雅的解決方案?在NSMutableArray中觀察計數
編輯:我糾正這NSMutableArray的當然..
我希望得到通知,當計數,即。 NSArray中的項目數目發生了變化.. 當然,如果我在控制添加和刪除對象到數組中,當然我不需要這個。但我不是,它在業務流程模型方面發生了不可預測的變化,並取決於外部因素。 有沒有一些簡單優雅的解決方案?在NSMutableArray中觀察計數
編輯:我糾正這NSMutableArray的當然..
你需要使用KVC。但如何去做呢?畢竟,NSMutableArray對於其突變方法或內容更改不符合鍵值編碼。答案是代理 - 作爲子類NS [Mutable]數組太麻煩了。
NSProxy是一個偉大的小類,您可以使用,就好像你是一個NSMutableArray攔截髮送到您的陣列中的消息,然後轉發他們到一些內部情況。不幸的是,它也不符合KVC標準,因爲KVC的內核生活在NSObject中。那麼我們必須使用它。樣本接口可能是這個樣子:
@interface CFIKVCMutableArrayProxy : NSObject {
NSMutableArray *_innerArray;
}
- (NSUInteger)count;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)addObject:(id)anObject;
- (void)removeLastObject;
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
//…
@end
正如你所看到的,我們模擬了NSMutableArray
的接口,這是必要的,因爲我們的代理應該實現的一切,就好像是一個NSMutableArray
。這也使得實現儘可能簡單,因爲我們可以將選擇器轉發到我們的內部指針NSMutableArray
。爲了簡便起見,我將只實現兩個方法告訴你什麼是一般的輪廓看起來像:
@implementation CFIKVCMutableArrayProxy
//…
- (NSUInteger)count {
return _innerArray.count;
}
- (void)addObject:(id)anObject {
[self willChangeValueForKey:@"count"];
[_innerArray addObject:anObject];
[self didChangeValueForKey:@"count"];
}
- (void)removeLastObject {
[self willChangeValueForKey:@"count"];
[_innerArray removeLastObject];
[self didChangeValueForKey:@"count"];
}
@end
如果你沒有機會結束這樣一個數組,然後嘗試重新思考你的代碼。如果外部依賴性迫使您進入這種角落,請嘗試刪除它。解決你自己的工具總是一件壞事。
一段時間過去了,幸運的改善將會在不在我控制範圍內的代碼部分實現 - 當模型更改時,包含數組的facade對象現在將發出NSNotifications。 您提出的解決方案是值得注意的,但是您錯過了一點但卻非常重要的事實,即我並未控制陣列。所以我不可能將代理對象注入到外觀而不是數組中。 – 2014-01-30 13:57:07
出於需要,我學到了一些新東西。 – naz 2014-10-03 00:12:32
@CodaFi感謝您的解釋:) – 2016-02-27 13:31:09
觀察一個mutableArray一個變化需要通過
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key
其使用給定的可變代理對象是符合KVO,即代理對象的任何變化發送意願/確實改變通知。
下面的試聽課每次添加或刪除對象時顯示現在全面推行
@interface DemoClass : NSObject
@property (nonatomic) NSMutableArray *items;
- (void)addItemsObserver:(id)object;
- (void)removeItemsObserver:(id)object;
@end
@implementation DemoClass
- (NSMutableArray *)items;
{
return [self mutableArrayValueForKey:@"_items"];
}
- (void)addItemsObserver:(id)object
{
[self addObserver:object forKeyPath:@"[email protected]" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}
- (void)removeItemsObserver:(id)object
{
[self removeObserver:object forKeyPath:@"[email protected]" context:nil];
}
@end
@interface ObservingClass : NSObject
@property (nonatomic) DemoClass *demoObject;
@end
@implementation ObservingClass
- (instanstype)init
{
if (self = [super init]) {
_demoObject = [DemoClass new];
[_demoObject addItemsObserver:self];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"is called on demoObject.items.count change");
}
- (void)dealloc
{
[_demoObject removeItemsObserver:self];
}
@end
的items
你會在控制檯中看到新的日誌(observeValueForKeyPath
被調用)。
自動合成的ivar _items
陣列的任何直接變化將沒有任何效果。
另請注意,您強烈需要將觀察者設置爲[email protected]
(觀察[email protected]
是無意義的)。
請注意,您不需要初始化_items
或self.items
。當您撥打items
獲得者時,將在幕後完成。
每當您更改「數組」items
時,您將獲得新對象_items
以及新地址。但我仍然可以通過items
proxy getter找到它。
您也可能想要'removeProxyItemsObserver:'方法。 – 2015-03-21 16:34:59
@AaronBrager,爲了完整而添加。謝謝。 – malex 2015-03-21 23:45:46
我對此並不是100%,但數組的keyPath和後綴'@ count'是KVC獲取此值的方式。所以也許你可以KVO觀察'array @ count'? https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE – joerick 2012-04-07 23:53:42