I'd like to implement KVO for an NSArray
property that is declared as readonly
. The getter for this readonly
property returns a copy of the private NSMutableArray
that backs the backs the public readonly
one:
In my .h
:
@interface MyClass : NSObject
@property (readonly, nonatomic) NSArray *myArray;
- (void)addObjectToMyArray:(NSObject *)obj;
- (void)removeObjectFromMyArray:(NSObject *)obj;
@end
And in my .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
In my tests, I am seeing an exception thrown when I call didChangeValueForKey:
. Is this the correct way to do this?
This is fragile, and
- (NSArray *)myArray
keeps returning different values for the same array which KVO doe not like.You'd be better of to define a private mutable array and a public read-only array. The when you make changes to the mutable array:
That way you can avoid all the will/has changed notifications because
self.myPublicReadOnlyArray
is KVC/KVO compliant.I don't have terribly much experience with this, but I post this answer in hopes that it will either solve your issue or lead you to a solution. In the past I've used this:
kYoutubeObserverKey
corresponds to:and I use a property of the same name in this class, hence the keyvalue name:
I would add an observer for your key and specify what change your interested in observing. Additionally, I'd keep your key naming consistent, meaning that if you're updating the private key, then observe that private key, not the public one. When the observer detects a change in the private key, then have your public key update as a result of that. For example:
According to the KVO docs, https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-BAJEAIEE, you need to implement
automaticallyNotifiesObserversForKey
, something like}
I have not tested this code, so apologies if I am on the wrong track.
I recommend that you don't use a separate property for the mutable array. Instead, have the array property backed by a mutable array variable. Then, implement the indexed collection mutating accessors and make all changes to the array through those. KVO knows to hook into those accessors and emit change notifications. In fact, it can emit better, more specific change notifications that can allow observers to be more efficient in how they respond.