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

Bib*_*ibs 0 objective-c key-value-observing ios

我想NSArray为声明为的属性实现KVO readonly.此readonly属性的getter 返回私有的副本,该私有NSMutableArray备份支持公共的副本readonly:

在我的.h:

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

在我的.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
Run Code Online (Sandbox Code Playgroud)

在我的测试中,我看到我打电话时抛出异常didChangeValueForKey:.这是正确的方法吗?

Ken*_*ses 6

我建议您不要为可变数组使用单独的属性.相反,让数组属性由可变数组变量支持.然后,实现索引集合变异访问器并通过它们对数组进行所有更改.KVO知道挂钩这些访问器并发出更改通知.事实上,它可以发出更好,更具体的变更通知,使观察者能够更有效地回应他们的反应.

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

@interface MyClass()
// Optional, if you want to be able to do self.myArray = <whatever> in your implementation
@property (readwrite, copy, nonatomic) NSArray *myArray;
@end

@implementation MyClass
{
    NSMutableArray *_myArray;
}

@synthesize myArray = _myArray;

// If you optionally re-declared the property read-write internally, above
- (void) setMyArray:(NSArray*)array {
    if (array != _myArray) {
        _myArray = [array mutableCopy];
    }
}

- (void) insertObject:(id)anObject inMyArrayAtIndex:(NSUInteger)index {
    [_myArray insertObject:anObject atIndex:index];
}

- (void) removeObjectFromMyArrayAtIndex:(NSUInteger)index {
    [_myArray removeObjectAtIndex:index];
}

- (void) addObjectToMyArray:(NSObject *)obj {
    [self insertObject:obj inMyArrayAtIndex:_myArray.count];
}

- (void) removeObjectToMyArray:(NSObject *)obj {
    NSUInteger index = [_myArray indexOfObject:obj];
    if (index != NSNotFound)
        [self removeObjectFromMyArrayAtIndex:index];
}
@end
Run Code Online (Sandbox Code Playgroud)