0

I'm looking for a way to access, at runtime, only the properties of an object that were declared in the header file for that class. I was able to retrieve all the properties of an object via the following code:

MyTest *myTestObj = [[MyTest alloc] init];
myTestObj.prop1 = @"prop1";
myTestObj.prop2 = @"prop2";

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

unsigned count;
objc_property_t *properties = class_copyPropertyList([myTestObj class], &count);

for (int i = 0; i < count; i++) {
    NSString *key = [NSString stringWithUTF8String:property_getName(properties[i])];
    id keyValue = [myTestObj valueForKey:key];

    if (keyValue != nil) {
        [dict setObject:keyValue forKey:key];
    }
}

free(properties);

(see Get an object properties list in Objective-C for more examples)

However, I need a way to limit the properties retrieved to only the ones declared in the .h file.

Basically, I'm looking for a way to access the object's public interface. Any suggestions on how to do this would be greatly appreciated.

I'm trying to save the state of my object in a dictionary so that it can be recreated later. Specifically, I'm trying to save it to the userInfo property of UILocalNotification.

I save the state of the object (in my case a UIViewController) to the userInfo property and create a local notification. When the user opens the app via a notification, I want to recreate the same UIViewController and set its state to what it was at the time the notification was created.

If there is a better way to do this that doesn't involve hardcoding then I'd love to hear some suggestions.

Community
  • 1
  • 1
Sid
  • 1,144
  • 10
  • 21
  • err what ? You have a 'myTestObj' ? And you want to access all the public properties ? – CW0007007 Jul 21 '14 at 15:38
  • It may be beneficial to specify *why* you need this functionality, as there may be other ways to accomplish what you're trying to do. – esqew Jul 21 '14 at 15:40
  • If your architecture depends on this it might be broken. – vikingosegundo Jul 21 '14 at 15:42
  • If the Class is your custom Class, maybe you can use prefix for private properties, like `_privateProperty`. – Wei Jul 21 '14 at 15:46
  • @Wei From Apple Coding Guidelines: `Don’t use the underscore character as a prefix for your private methods. Apple reserves this convention.`. – Keenle Jul 21 '14 at 15:49
  • @esqew: see my edit where I explain why I need this functionality. – Sid Jul 21 '14 at 16:53
  • 1
    Why not pass the object itself in the `userInfo` dict instead of all its attributes? – esqew Jul 21 '14 at 16:55
  • @esqew That won't work since the `userInfo` property will only accept types that are compatible with a property list – Sid Jul 21 '14 at 16:58
  • @Sid My apologies, I missed that. – esqew Jul 21 '14 at 17:32
  • @CW0007007 That's pretty much it. `myTestObj` is just some object. In my case, it will be a UIViewController – Sid Jul 21 '14 at 17:32
  • So why do you want to list all the properties .... Don't really follow with what the goal is here ... – CW0007007 Jul 21 '14 at 17:36
  • @CW0007007 Have a look at my question again. I've added an edit which explains what I'm trying to accomplish. – Sid Jul 21 '14 at 17:38

2 Answers2

1

Declaring a property in the header or in a class extension (or category somewhere else) does not change the available runtime information of the property.

I need a way to limit the properties retrieved to only the ones declared in the .h file

There's no way to do that.

After edit:

On the other hand it's a very common pattern to just add a property or method that returns a set of keys to be serialized. You could, for example, make all your model classes implement a method like the following:

+ (NSArray *)persistentKeys
{
    return @[ @"name", @"color", @"foo" ];
}

For each object to serialize your serialization code then has to walk the class and superclasses of the object and collect all persistent keys.

Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
  • Thanks for the suggestion to use a persistentKeys array. I thought about doing that as well but we come down to using some sort of hardcoding once again. This is just another way of doing what one would do if the NSCoding protocol was implemented. But, as you pointed out, there seems to be no way around some sort of hardcoding. – Sid Jul 21 '14 at 22:05
  • I've gone with the approach recommended by this answer of using a persistent keys array so I'm going to mark this as the answer. – Sid Jul 23 '14 at 00:19
1

What you are trying to do is bizarre. Please have a look at the NSCoding protocol which is designed to do what you want to do. Looking at properties declared in the header file is a totally weird idea. You have no idea whether or not setting the public properties would have the result you want.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 1
    yeah, I've looked at the NSCoding protocol but I was wondering if there was an alternative solution. I don't like the NSCoding protocol since it basically requires you to duplicate your property declarations within the `- (id)initWithCoder:(NSCoder *)decoder` and `- (void)encodeWithCoder:(NSCoder *)encoder` methods. So now, every time I add a new property I have to remember to update these two methods. – Sid Jul 21 '14 at 17:37
  • I agree that looking for public properties is not the right strategy to select persistent keys of a class. Yet, `NSCoding` does not help with that, either. – Nikolai Ruhe Jul 21 '14 at 19:15