1

In my project, I am getting passed a data object (XYZCustomClass) from a custom SDK. I will never need to modify this object, only use it and present its data in a UI. This custom data object has 5 normal string properties, and an NSDictionary type property called "addditionalProperties". The dictionary contains a set of key value pairs.

What I want in my client part, is to have real properties on my custom data object that would match those keys. Basically I want to have a nice interface with everything being a real property. I don't want to have some stuff hidden under keys, while other accessible normally.

I want to create a category on this data object that would declare 1) public readonly properties for each key 2) implement the getters that would retrieve the object for a particular key that is relevant for a particular property.

Working on 4.6.3 Xcode. Base SDK is 5.0. Is my approach ok? Will it work?

Remember, they are readonly, so please no associated object suggestions.

Earl Grey
  • 7,426
  • 6
  • 39
  • 59

3 Answers3

0

No, you cannot declare properties in a category. But , you can use a work-around, if the properties are not readonly, you can add methods, that will work like accessor methods:

eg.

//getter
-(obj *)readVal{

return self._obj;
}

//setter
-(void) update :(obj *)_val{
self._obj=_val;
}

You can use associative references. Quoting from apple's doc "It’s possible to interact directly with this runtime system, such as by adding associative references to an object. Unlike class extensions, associated references do not affect the original class declaration and implementation, which means you can use them with framework classes for which you don’t have access to the original source code." .

For description, see this SO answer

Community
  • 1
  • 1
zahreelay
  • 1,742
  • 12
  • 18
  • The reason is that a category adds beavior to an object but it does not override alloc, i. e. there is no way to allocate more space for the new properties. – Paul Jul 25 '13 at 14:05
  • Even if it's explicitly set to readonly and the getter is getting the object from an existing array based on key, and the array is in the original class anyway? I wont synthesise anything..Only declared readonly property in interface and a getter method in implementation. – Earl Grey Jul 25 '13 at 14:11
  • I tried it and it works. I am a bit disturbed by that :(, clearly one of the two sides is wrong. Is it Xcode - or - you? – Earl Grey Jul 25 '13 at 14:29
0

This works without visible problem. Is there some catch in this code?

DATA OBJECT

#import <Foundation/Foundation.h>

@interface CustomDataObject : NSObject

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSDictionary *additionalProperties;

@end

 #import "CustomDataObject.h"

 @implementation CustomDataObject

- (id)init
{
    self = [super init];
    if (self)
    {
        self.name = @"FirstName LastName";

        self.additionalProperties = @{@"amount"   : @"1000",
                                      @"state"    : @"happy"};
    }
    return self;
}

@end

CATEGORY

#import "CustomDataObject.h"

@interface CustomDataObject (additionalProperties)

@property (assign, nonatomic, readonly) NSString *amount;
@property (assign, nonatomic, readonly) NSString *state;

@end

#import "CustomDataObject+additionalProperties.h"

@implementation CustomDataObject (additionalProperties)

-(NSString *)amount
{
    return [self.additionalProperties objectForKey:@"amount"];
}

-(NSString *)state
{
    return [self.additionalProperties objectForKey:@"state"];
}

@end

VIEWCONTROLLER and the output

CustomDataObject *myObject = [[CustomDataObject alloc] init];

NSLog(@"%@", myObject.name);
NSLog(@"%@", myObject.amount);
NSLog(@"%@", myObject.state);

-----

2013-07-25 15:44:01.790 CatTest[30911:c07] FirstName LastName
2013-07-25 15:44:03.487 CatTest[30911:c07] 1000
2013-07-25 15:44:03.984 CatTest[30911:c07] happy
Earl Grey
  • 7,426
  • 6
  • 39
  • 59
0

You can get the DOT sugar syntax, if you simple declare the method on the .h file of the category like so:

@interface CustomDataObject (additionalProperties)

-(NSString *)amount;

@end

You then can:

NSLog(@"%@", myObject.amount);

If you don't want to declare a method for every element that might be inside the dictionary you can do something like:

@interface CustomDataObject (additionalProperties)

-(NSString *)additionalPropertiesKey:(NSString *)key;

@end

But you would lose your DOT syntax, because in this case the method expects a parameter.

Rui Peres
  • 25,741
  • 9
  • 87
  • 137