Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

test for read-only property vs. set/get key -- obj-c / cocoa

If all i have is a list of keys, is there an elegant way to test an object for read-only vs. read/write properties? I realize I could string-bang the key:

NSString *setterString = [@"set" stringByAppendingString:[someKeyString capitalizedString]];
BOOL isReadWrite = [myObject respondsToSelector:NSSelectorFromString(setterString)];

Or better yet try to set a value for the key and check for an NSUndefinedKeyException - but using exceptions for non-exceptional behavior seems like poor form.

To be clear, i'd like to programmatically audit an object's properties and tell the difference between, for instance,

@property (readonly) NSString *someReadOnlyKey
@property NSString *someReadWriteProperty

edit: To be more clear, it shouldn't matter if the keys are implemented as @propertys or manual getter/setter. Only concerned about public interface. And thanks for asking what I'm trying to accomplish - that's probably more important to get right in the first place.

I'm trying to sketch out some code that generates graphic representations of an object's keys. All the keys are known beforehand - but I won't always know which keys will be sett-able (it's up to the particular subclass to implement)

like image 812
Sam Hatchett Avatar asked Aug 31 '25 05:08

Sam Hatchett


1 Answers

You have two valid approaches:

  • the respondsToSelector: method
  • the runtime "trick" as exposed in Tommy's answer

I'll try to summarize the implication of both approaches, along with their drawbacks. You can then choose the approach more suitable to your needs.

Case 1

//MyClass.h

@property (readonly) NSString *someReadOnlyKey;
  • runtime => readonly
  • respondsToSelector => NO

Ok, everything works as expected.

Case 2

//MyClass.h

@property (readonly) NSString *someReadOnlyKey;

///////////////////////////////////////////////////////////////////////////

//MyClass.m

@property (readwrite) NSString *someReadOnlyKey;
  • runtime => readwrite
  • respondsToSelector => YES

If the property definition has been overridden, you'll get the actual property attribute being used. It doesn't matter whether you query about it from where the setter is visible, i.e. inside the class definition, or from outside. You will get the actual definition that has been used to synthesize the accessor methods.

Case 3

//MyClass.h

@property (setter=myCoolSetter) NSString *someReadOnlyKey;
  • runtime => readwrite
  • respondsToSelector => NO

With a custom setter name, the respondsToSelector trick won't work anymore, whereas the runtime is still providing the correct information.

Case 4

//MyClass.h

@property (readonly) NSString *someReadOnlyKey;

///////////////////////////////////////////////////////////////////////////

//MyClass.m

- (void)setSomeReadOnlyKey:(NSString *)someReadOnlyKey {
    _someReadOnlyKey = someReadOnlyKey;
}
  • runtime => readonly
  • respondsToSelector => YES

This time the runtime is failing, since the setter is there, but the property definition "doesn't know" about it.

like image 93
Gabriele Petronella Avatar answered Sep 02 '25 21:09

Gabriele Petronella