如何为只读派生的NSArray属性实现KVO?

时间:2015-05-01 14:55:53

标签: ios objective-c key-value-observing

我想为声明为readonly的{​​{1}}属性实现KVO。此readonly属性的getter返回私有NSMutableArray的副本,该副本支持公共readonly一个:

在我的.h

@interface MyClass : NSObject
@property (readonly, nonatomic) NSArray *myArray;
- (void)addObjectToMyArray:(NSObject *)obj;
- (void)removeObjectFromMyArray:(NSObject *)obj;
@end

在我的.m

@interface MyClass()
@property (strong, nonatomic) NSMutableArray *myPrivateArray;
@end

@implementation MyClass

- (NSArray *)myArray {
    return (NSArray *)[self.myPrivateArray copy];
}

- (void) addObjectToMyArray:(NSObject *)obj {
    [self willChangeValueForKey:@"myArray"];
    [self.myPrivateArray addObject:obj];
    [self didChangeValueForKey:@"myArray"];
}

- (void) removeObjectToMyArray:(NSObject *)obj {
    [self willChangeValueForKey:@"myArray"];
    [self.myPrivateArray removeObject:obj];
    [self didChangeValueForKey:@"myArray"];
}
@end

在我的测试中,当我拨打didChangeValueForKey:时,我看到一个例外。这是正确的方法吗?

3 个答案:

答案 0 :(得分:0)

根据KVO文档https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-BAJEAIEE,您需要实施automaticallyNotifiesObserversForKey,例如

    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {

BOOL automatic = NO;
if ([theKey isEqualToString:@"myArray"]) {
    automatic = NO;
}
else {
    automatic = [super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;

}

我还没有测试过这段代码,如果我走错了路,那就道歉了。

答案 1 :(得分:0)

我对此没有太多经验,但我发布这个答案,希望它能解决您的问题或引导您找到解决方案。过去我用过这个:

-(void)viewDidLoad{
    [self addObserver:self forKeyPath:kYoutubeObserverKey options:NSKeyValueObservingOptionNew context:nil];
}

-(void) addLocatedYoutubeURLToList:(NSString *)youtubeURL{

    // -- KVO Update of Youtube Links -- //
    [self willChangeValueForKey:kYoutubeObserverKey
                withSetMutation:NSKeyValueUnionSetMutation
                   usingObjects:[NSSet setWithObject:youtubeURL]];

    [self.youtubeLinksSet addObject:youtubeURL];

    [self didChangeValueForKey:kYoutubeObserverKey
               withSetMutation:NSKeyValueUnionSetMutation
                  usingObjects:[NSSet setWithObject:youtubeURL]];
}

kYoutubeObserverKey对应于:

static NSString * const kYoutubeObserverKey = @"youtubeLinksSet";

我在这个类中使用了同名的属性,因此键值名称为:

@property (strong, nonatomic) NSMutableSet * youtubeLinksSet;

我会为你的密钥添加一个观察者,并指明你对观察感兴趣的变化。此外,我会保持您的密钥命名一致,这意味着如果您正在更新私钥,那么请观察该私钥,而不是公钥。当观察者检测到私钥发生变化时,请更新公钥。例如:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    NSNumber * keyValueChangeType = change[@"kind"];
    if ([keyValueChangeType integerValue] == NSKeyValueChangeInsertion) {

        if ([keyPath isEqualToString:kYoutubeObserverKey] ) {
            //code and such...
        }
    }
}

答案 2 :(得分:0)

这很脆弱,- (NSArray *)myArray不断为KVO不喜欢的同一个数组返回不同的值。

您最好定义私有可变数组和公共只读数组。当您对可变数组进行更改时:

self.myPublicReadOnlyArray=self.myMutableArray.copy;

这样您就可以避免所有意愿/已更改通知,因为self.myPublicReadOnlyArray符合KVC / KVO。