20

I've attempted to observe the (readonly) visibileViewController property of a UINavigationController with no success. I was able to successfully observe a readwrite property I defined myself for testing purposes on another class.

Is it possible to observer readonly attributes?

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
user53937
  • 623
  • 1
  • 9
  • 10

5 Answers5

22

Yes, it is possible to observe read-only properties. However, if the object that declares that property makes changes to the value of that property in a way that is not Key-Value Observing compliant (e.g. changes the value of the instance variable backing that property directly without seding willChangeValueForKey: and didChangeValueForKey: notifications) then observers will not automatically be notified by the KVO system. If you can verify that the value of this property is changing and your observers are not being notified, I would (1) post some code here or elsewhere so that others can help you find your bug and (2) if there is no bug in your code, file a bug on Apple's radar.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
Barry Wark
  • 107,306
  • 24
  • 181
  • 206
16

Yes. An easy way to implement it in your own class is to declare the property as readonly in the .h file and redeclare it as writable in the private interface in the .m file. That way you can synthesize and get the change notifications handled automatically.

In the .h file:

@interface MyClass : NSObject
@property (nonatomic, readonly) BOOL foo;
@end

In the .m file

@interface MyClass ()
@property (nonatomic, readwrite) BOOL foo;
@end

@implementation MyClass

@synthesize foo;

- (void)bar {
    // Observers will see the change
    self.foo = YES;
}

@end
Anton Holmberg
  • 1,113
  • 12
  • 15
  • I believe this will not stop performing `myObject.foo = YES` from outside this class (unless, maybe, ARC screams it can't see a declaration) – user1071136 Aug 21 '12 at 13:56
  • 1
    I didn't think this would work because of the clash in synthesize methods, but it appears to work for me! Publicly, the method is not available, but I can set it privately. – jowie Aug 29 '12 at 16:04
  • 1
    This is exactly how to do this and as Jowie pointed out, simply set it privately. Note though, if you setup _foo and set that, then KVO does not fire. – Arvin Sep 19 '12 at 13:39
2

You can certainly observe readonly properties but be aware that in order for KVO to work you need to be KVC compliant - which means using either the setter/getter for a property (since you're readonly, you don't get a setter for free via @synthesize) or the property's -setValue:forKey: method.

wisequark
  • 3,288
  • 20
  • 12
0

A slightly different answer:

@interface MyClass : NSObject
@property (nonatomic, readonly) BOOL foo;
@end

In the .m file

@interface MyClass ()
@property (nonatomic, readwrite) BOOL foo;
@end

@implementation MyClass

+ (NSSet *)keyPathsForValuesAffectingFoo {
    return [[NSSet alloc] initWithObjects:NSStringFromSelector(@selector(foo)), nil];
}

@end
-2

This is definitely be possible using NSKeyValueObserving. Properties actually have getter/setter implementations, they are just done for you by the compiler via the @synthesize keyword in an Objective-C classes implementation. Since the key-value observing protocol is based on the standard getter/setter conventions in Objective-C, observing properties works fine. The documentation (linked above) even mentions class properties by name:

"The NSKeyValueObserving (KVO) informal protocol defines a mechanism that allows objects to be notified of changes to the specified properties of other objects."

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
Nick Haddad
  • 8,767
  • 3
  • 34
  • 38