I am doing a value object / Entity, that holds data for my model.
I get the data from a web service as JSON, now, instead of moving all the different objects from the parsed JSON over into different properties on my Entity. i.e. reading out the NSString for the #"name" key and setting it to [Entity setName:[JSONDictionary objectForKey:#"name"] etc. My Entity has one actual property,
NSDictionary *dataDictionary, this property hold the JSON dictionary as it left the parser.
Now when I need the name value I write an accessor that looks like this:
- (NSString*) name {
return [self.dataDictionary objectForKey:#"name"];
}
This is nice, I don't have to do any work unless there is a request for that particular property.
Now my question is how do I best tell the compiler that the accessor exists, but does not hold a "real" property.
I have this in my interface:
#property(nonatomic, retain) NSString *name;
And the #synthesize in my implementation, but this seems to create an overhead in my logic. Objective C will, as far as I understand, make a room in memory for me to store an object of type NSString when I do the #property(nonatomic, retain) and technically I don't need this as I am already storing this value in the the NSDictionary *dataDictionary
If I make it #dynamic I guess I would also have to provide a setter, which I would never need.
So, Is there a syntax that lets me create the illusion to all objects accessing the Entity that these are "normal" properties, but internally in the Entity not alloc/store unnecessary objects or write more code than is needed?
Declare a name method in your interface, not a property.
- (void)name;
Related
I am using Key-Value Coding to simplify updating instances of a model class:
#interface NewsItem : NSObject
{
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSString *link;
#property (nonatomic, copy) NSString *date;
using:
SEL selectorName = NSSelectorFromString(elementName);
if ([self.newsItem respondsToSelector:selectorName])
{
NSString *sanitisedElement = [self sanitiseElement:self.currentElementData];
[self.newsItem setValue:sanitisedElement forKey:elementName];
}
This works well but the 'description' property doesn't 'smell' right to me as it has overridden the base NSObject description getter (+ (NSString *)description). If the description getter is invoked now it will return irrelevant information when the caller would be expecting a description of the class.
Is it possible to safely proceed with Key-Value Coding for this class (given that I am bound to these property names by the external data source)? Or would it be wise to change the property names and manually check keys/set values instead?
You could override description in your class. This method is usually used only for debugging
and no caller can expect a specific output of that method.
But I see more general problems in your code. It is only checked that a method with the
given name exists. This does not imply that this method corresponds to a property, and even then, it does not imply that there is a setter for that property.
For example, every NSObject responds to the selector "init", so if the external
data source sends that key as "elementName", your code would immediately crash.
Therefore, an explicit list of "known keys" is needed. But then you can as well
use a mapping (NSDictionary) from external element names to internal properties
to avoid any conflicts.
I think that you are confusing methods with properties, and you are making things more complicated that how they are.
Is enough that, given an elementName that contains directly the setter name (i.e.: setDate), you invoke the selector passing that argument the object argument:
SEL selectorName = NSSelectorFromString(elementName); // elementName something like "setDate"
if ([self.newsItem respondsToSelector:selectorName])
{
[self.newsItem performSelector: selectorName withObject: sanitisedElement];
}
As for the description method, it has overridden NSObject's description, so you have two choices: name it in another way, or leave it like it is, and invoke it on super when you need the object description, with the help of Objective-C runtime:
struct objc_super superclass= { self.newItem, [self.newItem superclass] };
NSString* desc= objc_msgSendSuper(&superclass, #selector(description));
You can always override inherited methods.
By creating a property whose getter is the same as the signature of An inherited method, you are overriding it.
Is it bad? Yes if your implementation is not useful for debugging.
As best practice for KVC and KVO purposes it is a good idea to avoid potentially clashing with common inherited methods properties and ivars.
The common approach to this is to make longer property and method names and to make them more likely to be unique. One common way is by prefixing all yours with an abbreviation common to your class or framework or code.
Using something commonly used by Apple is likely to bite you in a rare and hard to debug way.
It's especially a bad idea to do this when core data is involved.
Don't be reluctant to make things longer. Code completion will type for you. Plus, a nice side effect of class specific prefixing is pseudo not only the pseudo namespace but that your class specific properties, variables, constants and methods will bubble up first in code completion.
I think this is a simple issue but I have somehow leaked object in core data. I have a simple one to one relation in core data.
Person <--------> Address
-name -city
-email -country
The person model was relatively simple with just few attributes. But, I wanted to add the getter in Person class to access the city and country from the person class itself. So, I did something like,
#interface Person:NSManagedObject
#property(nonatomic, strong) NSString *name;
#property(nonatomic, strong) NSString *email;
#property(nonatomic, strong) Address *address;
-(NSString*)city;
-(NSString*)country;
#end
#implementation Person
-(NSString*)city{
[self willAccessValueForKey:#"address"];
NSString *c = [self valueForKeyPath:#"address.city"];
[self didAccessValueForKey:#"address"];
}
-(NSString*)country{
[self willAccessValueForKey:#"address"];
NSString *c = [self valueForKeyPath:#"address.country"];
[self didAccessValueForKey:#"address"];
}
#end
With these getter I have been able to access the city with just simple getters in Person model as;
person.city and person.country
But, I feel this is not the correct way to do it. How do I implement this feature to ensure that the memory is not leaked.
You can not access city or country directly from Person,
you can access like....
Person.Address.city
Person.Address.country
and no need of implement the:
-(NSString*)city;
-(NSString*)country;
You forgot the return statements in the code, but I guess they are there in the actual code you are using.
I do not see any leak in the code itself. Remember however that you are responsible for faulting everything when done as Core Data relationships inherently create retain cycles. See Core Data And Retain Cycles
As Ganee says, you can just access
person.address.city
but if you absolutely need the city method, you should use the generated properties:
- (NSString*)city {
return address.city;
}
though this hides your relationship access so make sure that's what you want.
In regards to your memory leak, you need a really, really, really good reason to not use ARC for new projects.
I often have a hard time deciding if certain data should be exposed through a property or a method. You can say "use properties for object state", but that's not very satisfying. Take this example for instance:
- (NSString *)stringOne
{
return _stringOne;
}
- (NSString *)stringTwo
{
return _stringTwo;
}
- (NSString *)mainString
{
return [_stringOne length] > 0 ? _stringOne : _stringTwo;
}
It's clear that stringOne and stringTwo should be properties because they are clearly object state. It's not clear, however, if mainString should be a property. To the end user mainString acts like state. To your object, mainString is not state.
This example is contrived but hopefully you get the idea. Yes, properties are nothing more than a convenient way to create getters and setters but they also communicate something to the user. Does anyone have decent guidelines for deciding when to use a property vs a method.
Hiding the split between "true" state (string1 and string2 in your example) and "dynamic" state (mainString) is, I would say, exactly what properties are for.
The canonical example would probably be an object that represents a person, with given and family names as "state". A third piece of state, "full name" can be presented from those two pieces, but clients have absolutely no reason to know whether the full name is constructed on demand, or is created and stored when both of its pieces are set. It simply doesn't matter.
Properties are an interface -- what bits of data does this class provide to its clients (and what can the clients configure about the class)? The implementation of each property is encapsulated and does not affect its status as a property.
In ObjC, of course, we use methods to access properties. Other methods, however, represent actions that an object can take, possibly being passed some piece of data to operate on.
Another consideration to take into account : do you want to store the value of the property ? (via NSCoding or in Core Data for example)
I guess you NEED to create properties for things you need to "save" (in "encodeWithCoder" for instance. Deciding what you want to put in encodeWithCoder could help you decide which way you want to define things).
For things you don't need to save and can recalculate easily, you have the choice between a method and a readonly property (which is equivalent under the hood : a readonly property only creates a getter accessor method, and does not have an instance variable to back it). So that's more a question of style.
Speaking of style, if you use dot notation for properties only (as I do), you'd maybe wonder :
- do I want to access the full name as foo.fullName, and not make a difference with other properties like foo.firstName and foo.lastName ?
- or do you want to make a difference by accessing the full name with [foo fullName], showing to the world that this is calculated ?
I created an app for following stock quotes, and the model was inspired from an example in the Big Nerd Ranch book about Objective C (good read, by the way).
Here is how properties and methods are defined :
// properties
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *symbol;
#property (nonatomic, copy) NSString *currency;
#property (nonatomic, copy) NSString *market;
#property (nonatomic) int numberOfShares;
#property (nonatomic) double purchaseSharePrice;
#property (nonatomic) double currentSharePrice;
// Stock Calculation methods
- (double)costInLocalCurrency; // purchaseSharePrice * numberOfShares
- (double)valueInLocalCurrency; // currentSharePrice * numberOfShares
- (double)gainOrLossInLocalCurrency // valueInLocalCurrency - costInLocalCurrency
You can see that they are clearly distinguished.
The BNR does not use dot notation at all in their book, so it would all look the same : [foo currentSharePrice] or [foo valueInLocalCurrency], but as I use dot notation for properties, I would make a difference in style between foo.currentSharePrice and [foo valueInLocalCurrency].
Hope this is helpful.
By design, you should always respect the end user - if you think it's object state for the user of your class (which it apparently is), then go ahead and make a property out of it.
is it possible to specify that a NSMutableArray can only contain a certain type of objects.
For example, if I want to store only this kind of objects :
#interface MyObject : NSObject {
UInt8 value;
}
In order to be able to use the instance variable like this :
- (void)myMethod:(NSMutableArray *)myArray{
for (id myObject in myArray){
[self otherMethod:myObject.value];
}
}
because I'm getting this error :
request for member 'value' in something not a structure or union
Thank you for your help
It sounds like you're coming from a Java/C# type background where limits can be imposed on collections.
Collections in Cocoa don't follow that pattern. There is no way to set a restriction on what type of objects can be inserted (unless you write a wrapper class that enforces this).
Objective-C, by design, follows the "if it walks like a duck and it quacks like a duck, then it most probably is a duck" philosophy. That is to say that rather than checking whether an object is a particular type, you should be checking whether it can do what you want it to do regardless of its type.
You can do this using respondsToSelector:.
Finally, your problem isn't actually related to the fact that the array has no restrictions. Your object doesn't appear to declare the instance variable value as a property, or expose any accessor methods for it.
This is why you're seeing the error when you try myObject.value. That syntax in Objective-C is how you access properties.
The default scope for instance variables in Objective-C is #protected, which means anything outside your class can't access them without going through an accessor method of some kind.
You need to declare and define the methods - (UInt8)value and - (void)setValue:(UInt8)aValue and use them.
Alternatively, you could declare it as a property.
You are getting that error, because for as far as Objective-C is concerned, myObject is of the non-type id, which doesn't support the value property. To make Objective-C aware of the fact it's always dealing with a MyObject in this loop, you'll have to tell it the myObject object is an instance of MyObject.
for (MyObject *myObject in myArray) {
Also, you have to make sure the value ivar is accessible using dot-notation by implementing getter and setter methods for it. You can do this yourself by implementing -value and -setValue:, or you can use #property and #synthesize to let Objective-C do this.
Objective-C doesn't work like that. You need to use [myObject value] (which will work irrespective of the kind of object, as long as it responds to -[value]. If you only want one type of objects in it, insert only that type of objects.
You would have to write a wrapper-class for the NSMutableArray, see for example this question.
Subclass NSMutableArray and override methods that mediate the addition of objects to the array. You would check the object type in these overridden methods, only calling [super addObject:xyz] if the type is accepted.
maybe you can use protocol:
#protocol Person <NSObject>
#end
#interface Person : NSObject <Person>
#end
to use:
NSArray<Person>* personArray;
Let's say I have a class called SomeClass with a string property name:
#interface SomeClass : NSObject
{
NSString* name;
}
#property (nonatomic, retain) NSString* name;
#end
I understand that name may be assigned a NSMutableString in which case this may lead to errant behavior.
For strings in general, is it always a good idea to use the copy attribute instead of retain?
Is a "copied" property in any way less efficient than such a "retain-ed" property?
For attributes whose type is an immutable value class that conforms to the NSCopying protocol, you almost always should specify copy in your #property declaration. Specifying retain is something you almost never want in such a situation.
Here's why you want to do that:
NSMutableString *someName = [NSMutableString stringWithString:#"Chris"];
Person *p = [[[Person alloc] init] autorelease];
p.name = someName;
[someName setString:#"Debajit"];
The current value of the Person.name property will be different depending on whether the property is declared retain or copy — it will be #"Debajit" if the property is marked retain, but #"Chris" if the property is marked copy.
Since in almost all cases you want to prevent mutating an object's attributes behind its back, you should mark the properties representing them copy. (And if you write the setter yourself instead of using #synthesize you should remember to actually use copy instead of retain in it.)
Copy should be used for NSString. If it's Mutable, then it gets copied. If it's not, then it just gets retained. Exactly the semantics that you want in an app (let the type do what's best).
For strings in general, is it always a good idea to use the copy attribute instead of retain?
Yes - in general always use the copy attribute.
This is because your NSString property can be passed an NSString instance or an NSMutableString instance, and therefore we can not really determine if the value being passed is an immutable or mutable object.
Is a "copied" property in any way less efficient than such a "retain-ed" property?
If your property is being passed an NSString instance, the answer is "No" - copying is not less efficient than retain.
(It's not less efficient because the NSString is smart enough to not actually perform a copy.)
If your property is passed an NSMutableString instance then the answer is "Yes" - copying is less efficient than retain.
(It's less efficient because an actual memory allocation and copy must occur, but this is probably a desirable thing.)
Generally speaking a "copied" property has the potential to be less efficient - however through the use of the NSCopying protocol, it's possible to implement a class which is "just as efficient" to copy as it is to retain. NSString instances are an example of this.
Generally (not just for NSString), when should I use "copy" instead of "retain"?
You should always use copy when you don't want the internal state of the property changing without warning. Even for immutable objects - properly written immutable objects will handle copy efficiently (see next section regarding immutability and NSCopying).
There may be performance reasons to retain objects, but it comes with a maintenance overhead - you must manage the possibility of the internal state changing outside your code. As they say - optimize last.
But, I wrote my class to be immutable - can't I just "retain" it?
No - use copy. If your class is really immutable then it's best practice to implement the NSCopying protocol to make your class return itself when copy is used. If you do this:
Other users of your class will gain the performance benefits when they use copy.
The copy annotation makes your own code more maintainable - the copy annotation indicates that you really don't need to worry about this object changing state elsewhere.
I try to follow this simple rule:
Do I want to hold on to the value of the object at the point in time when I am assigning it to my property? Use copy.
Do I want to hold on to the object and I don't care what its internal values currently are or will be in the future? Use strong (retain).
To illustrate: Do I want to hold on to the name "Lisa Miller" (copy) or to I want to hold on to the person Lisa Miller (strong)? Her name might later change to "Lisa Smith", but she will still be the same person.
Through this example copy and retain can be explained like:
NSMutableString *someName = [NSMutableString stringWithString:#"Chris"];
Person *p = [[[Person alloc] init] autorelease];
p.name = someName;
[someName setString:#"Debajit"];
if the property is of type copy then ,
a new copy will be created for the [Person name] string that will hold the contents of someName string. Now any operation on someName string will have no effect on [Person name].
[Person name] and someName strings will have different memory addresses.
But in case of retain,
both the [Person name] will hold the same memory address as of somename string, just the retain count of somename string will be incremented by 1.
So any change in somename string will be reflected in [Person name] string.
Surely putting 'copy' on a property declaration flies in the face of using an object-oriented environment where objects on the heap are passed by reference - one of the benefits you get here is that, when changing an object, all references to that object see the latest changes. A lot of languages supply 'ref' or similar keywords to allow value types (i.e. structures on the stack) to benefit from the same behaviour. Personally, I'd use copy sparingly, and if I felt that a property value should be protected from changes made to the object it was assigned from, I could call that object's copy method during the assignment, e.g.:
p.name = [someName copy];
Of course, when designing the object that contains that property, only you will know whether the design benefits from a pattern where assignments take copies - Cocoawithlove.com has the following to say:
"You should use a copy accessor when the setter parameter may be mutable but you can't have the internal state of a property changing without warning" - so the judgement as to whether you can stand the value to change unexpectedly is all your own. Imagine this scenario:
//person object has details of an individual you're assigning to a contact list.
Contact *contact = [[[Contact alloc] init] autorelease];
contact.name = person.name;
//person changes name
[[person name] setString:#"new name"];
//now both person.name and contact.name are in sync.
In this case, without using copy, our contact object takes the new value automatically; if we did use it, though, we'd have to manually make sure that changes were detected and synced. In this case, retain semantics might be desirable; in another, copy might be more appropriate.
#interface TTItem : NSObject
#property (nonatomic, copy) NSString *name;
#end
{
TTItem *item = [[TTItem alloc] init];
NSString *test1 = [NSString stringWithFormat:#"%d / %#", 1, #"Go go go"];
item.name = test1;
NSLog(#"-item.name: point = %p, content = %#; test1 = %p", item.name, item.name, test1);
test1 = [NSString stringWithFormat:#"%d / %#", 2, #"Back back back"];
NSLog(#"+item.name: point = %p, content = %#, test1 = %p", item.name, item.name, test1);
}
Log:
-item.name: point = 0x9a805a0, content = 1 / Go go go; test1 = 0x9a805a0
+item.name: point = 0x9a805a0, content = 1 / Go go go, test1 = 0x9a84660
You should use copy all the time to declare NSString property
#property (nonatomic, copy) NSString* name;
You should read these for more information on whether it returns immutable string (in case mutable string was passed) or returns a retained string (in case immutable string was passed)
NSCopying Protocol Reference
Implement NSCopying by retaining the original instead of creating a
new copy when the class and its contents are immutable
Value Objects
So, for our immutable version, we can just do this:
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
Since name is a (immutable) NSString, copy or retain makes no difference if you set another NSString to name. In another word, copy behaves just like retain, increasing the reference count by one. I think that is an automatic optimization for immutable classes, since they are immutable and of no need to be cloned. But when a NSMutalbeString mstr is set to name, the content of mstr will be copied for the sake of correctness.
If the string is very large then copy will affect performance and two copies of the large string will use more memory.