Reputation: 6118
I have a class that represents some data.
I'm getting this data from a Web Service in the JSON format.
The web service does not conform to the Objective - C naming convention. More specifically, all the attributes of an object starts with capital letter, for example Name
.
I want to be able to utilize the built-in KVC but still build my objects with the Objective-C naming convention.
So in my public class declaration I'm declaring one property:
@interface TVPage : NSObject
@property (nonatomic, copy) NSString *name;
@end
And In my *.m file I'm declaring a category extension to conform to the Web Service naming convention:
@interface TVPage ()
@property (nonatomic, copy , getter = name , setter = setName:) NSString *Name;
@end
In the private property I'm specifying the getter and setter that I want to actually access the data.
All I want to achieve is just another method, called Name
that will actually call name
behind the scene. (setName:
actually fits for both Name
and name
)
My question is, when I'm synthesizing the properties like that:
@implementation TVPage
@synthesize name;
@synthesize Name;
@end
Will it generate two different Instance Variables called Name
and name
or is it smart enough to understand not to do that and create only one named name
?
Can I tell the compiler explicitly - "Do not generate IVar for this property"?
Thanks!
EDIT:
A lot of you asked me what exactly am I trying to achieve here. Well, what I'm trying to do is to make my life easier when it comes to parsing the data returned from the web service.
The data is returned as a JSON String. That means that when I'll parse it, I'll probably get back NSDictionaries to represent the data.
I want to easily create objects that I designed to hold this data, because it's not convenient, safe or readable to work with dictionaries as a data model.
Now, the Key-Value Coding features allow me to set the attributes of an object, directly from a dictionary using setValuesForKeysWithDictionary:
But this will work only if my object actually have accessor methods with the same names as the dictionary's keys. If there is a key that don't have a matching attribute in my object, I'll get an exception from setValue:forUndefinedKey:
.
To avoid that I want to create Facade Interface that will conform to the Key-Value Coding methods implied by the attribute names from the server. At the same time I want that the implementation of that interface will access the same data that the "regular" interface access.
Upvotes: 1
Views: 2059
Reputation: 90117
As I said, write some test code and then don't continue with whatever you are doing.
@property (strong, nonatomic) NSString *name;
@property (nonatomic, copy , getter = name , setter = setName:) NSString *Name;
and @synthesize
both. To see what happens we put some logging code into our s/getter, like this.
- (void)setName:(NSString *)aName {
NSLog(@"setter called");
name = aName;
}
- (NSString *)name {
NSLog(@"getter called");
return name;
}
and now have some testing fun.
NSLog(@"setValue:forKey: with Key name");
[self setValue:@"Name" forKey:@"name"];
NSLog(@"setValue:forKey: with Key Name");
[self setValue:@"Name" forKey:@"Name"];
NSLog(@"valueForKey: with Key name");
NSLog(@"ptr: %p", [self valueForKey:@"name"]);
NSLog(@"valueForKey: with Key Name");
NSLog(@"ptr: %p", [self valueForKey:@"Name"]);
NSLog(@"\n");
NSLog(@"calling setter via dot-notation for name");
self.name = @"foo";
NSLog(@"calling setter via dot-notation for Name");
self.Name = @"foo";
NSLog(@"calling getter via dot-notation for name");
NSLog(@"ptr: %p", self.name);
NSLog(@"calling getter via dot-notation for Name");
NSLog(@"ptr: %p", self.Name);
let's run it. et voila.
[4115:f803] setValue:forKey: with Key name
[4115:f803] setter called
[4115:f803] setValue:forKey: with Key Name
[4115:f803] setter called
[4115:f803] valueForKey: with Key name
[4115:f803] getter called
[4115:f803] ptr: 0x36d8
[4115:f803] valueForKey: with Key Name <-----
[4115:f803] ptr: 0x0 <-----
[4115:f803]
[4115:f803] calling setter via dot-notation for name
[4115:f803] setter called
[4115:f803] calling setter via dot-notation for Name
[4115:f803] setter called
[4115:f803] calling getter via dot-notation for name
[4115:f803] getter called
[4115:f803] ptr: 0x3758
[4115:f803] calling getter via dot-notation for Name
[4115:f803] getter called
[4115:f803] ptr: 0x3758
You see? The custom getter name
is not called for valueForKey:@"Name"
. However the custom setter is called. But probably only because you can't capitalize a capital letter.
I hope you don't just blindly use setValuesForKeysWithDictionary:
with a bunch of values. You have to validate those keys anyway, because you don't want to call that method for keys like self
, description
and so on. So while you validate the keys just "decapitalize" the names of the keys.
Removing the capital letter is IMHO a much cleaner way because it doesn't fail for half of the accessor methods like it happened with those strange shadow variables.
Upvotes: 3
Reputation: 1430
Yes you can tell the compiler. You need to not use @synthesize
but @dynamic
which just tells the compiler to trust you that there is an implementation of that somewhere, and don't throw warnings etc.
Upvotes: 1