Should I have to manually copy object in custom setter with copy property in objective-c?
For example,
I have a property:
#property (copy, nonatomic) NSString *someString;
and custom setter:
- (void)setSomeString:(NSString *)someString
{
//option 1
_someString = someString;
//option 2
_someString = [someString copy];
//do other stuff
}
Is it option 1 enough for custom setter or I have to use option 2 instead in order to have copied object?
You can do whatever you like but you should use the second option.
This is because it will be something like code documentation if other developer see it he or she will know that you copy the string just by looking at:
#property (copy, nonatomic) NSString *someString;
The same if you use retain/assign it's best practice to retain/assign object in custom setter. It will make your code more clearer more documented and much more understandable for others developers.
You Must use "option 2" because you are using "copy" for your property and statement :
_someString = [someString copy];
would create a new object in memory and assign it to your property object.
If you write your own custom setter, then you are 100% responsible for everything it does. In your case, you are 100% responsible for the bug that you introduce with option 1 of your code: If I set someObject.someString to a mutable string and change the string later, then the string in your object will change which is most definitely not what you expect from a copy property.
In addition, if you have both a custom setter and getter (or a custom getter for a read-only property) so there is no compiler generated getter or setter, the compiler doesn't create the instance variable for you; you'll have to do that yourself.
You should also notice that "copy" of immutable objects doesn't actually copy them but just retains them, so usually the "copy" operation is really cheap, and when I pass a mutable object, "copy" was most likely what you wanted anyway.
Go with option 2 if you want to make own setter but don't forget to add the condition before the statement like...
if(_someString) {
[_someString release];
}
Note:- In case of ARC use statement "_someString = nil" instead
of "[_someString release]";
Related
I have read through many materials online which all explain when people should use "copy" instead of "strong".
"The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute..."
And there are plenty of example codes showing when using "copy", the original value stays the same.
However, I'm new to Objective-C. I really want to know how to use the newly assigned value. Where is the "new instance(copy)" with the "new value"? Do I need any additional methods to change the original value if I want to?
It will be great if someone can share an example for this part not the one proving the original value is not changed, which is everywhere.
What the copy attribute does behind the scenes is to create a setter like this:
- (void)setMyCopiedProperty:(MyClass *)newValue {
_myCopiedProperty = [newValue copy];
}
this means that whenever someone does something like this object.myCopiedProperty = someOtherValue;, the someOtherValue is sent a copy message telling it to duplicate itself. The receiver gets then a new pointer (assuming copy is correctly implemented), to which no-one excepting the receiver object has access to.
You can look at copy as being exclusive in some kind of way:
the clients that set the property don't have access to the actual set value
the receiver doesn't have access to the original passed value.
Beware of the caveats, though:
a copied NSArray doesn't copy its objects, so you might end up thinking that a #property(copy) NSArray<MyClass *> *myProperty is safe, however while the array itself is safe from being modified, the objects held by the array share the same reference. Same is true for any collection class (NSDictionary, NSSet, etc)
if the property matches to a custom class you need to make sure the copy method does its job - i.e. creating a new object. This happens for all Cocoa/CocoaTouch classes that conform to NSCopying, however for other classes this might or not be true, depending on implementation (myself I didn't saw yet a class that lies about its copy method, however you never know)
Try this:
Model.h
#interface Model: NSObject
#property (nonatomic,strong)NSString *firstName;
#property (nonatomic,copy) NSString *lastName;
#end
ViewController.m
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
Model *model = [[Model alloc]init];
NSMutableString *str = [[NSMutableString alloc]initWithString:#"test"];
model.firstName = str;
model.lastName = str;
NSLog(#"%#, %#", model.firstName, model.lastName);
[str appendString:#"string"];
NSLog(#"%#, %# ", model.firstName, model.lastName);}
Output :
1st Nslog = "test", "test"
2nd Nslog = "teststring", "test"
An instance of a class is a discrete copy. When you assign an instance of a class to be the value of a property with the copy attribute, a clone of that instance is made and that clone becomes the value of the property. There is no relationship between the original and its clone, so the property does not have access to the original instance at all. Changing an attribute of the property's value is changing the clone.
Note:
If you implement the setter for a copy property, it is your responsibility to ensure it actually creates a copy. As is true with all the attributes for a property, they only have meaning when the compiler is generating (synthesizing) the setter and/or getter for you.
This question already has answers here:
Is there a difference between an "instance variable" and a "property" in Objective-c?
(6 answers)
Closed 9 years ago.
What is the difference between these declarations, lets call them red and orange:
pros, cons?
The red set is properties, and the orange set is instance variables.
A property declaration tells the compiler to define a getter method, and possibly a setter method. (No setter method if the property is readonly.)
In newer versions of Objective C, declaring a property also creates an instance variable that is used to save values for the property. By convention the instance variable has the same name as the property, but with an "_" prefix. There is a way to change the name of the instance variable, but let's ignore that for now.
The property foo:
#property (nonatomic, strong) NSString *foo;
Would have a getter method:
- (NSString *) foo;
and a setter method
- (void) setFoo: (NSString *) foo;
That enables you to use code like this:
NSString *aString = self.foo;
or
NSString *aString = [self foo];
(2 different, equally valid ways of invoking the getter)
And invoking the setter
self.foo = #"a string";
or
[self setFoo: #"a string"];
(2 different, equally valid ways of invoking the setter)
Properties are really useful when you want to create a public interface to get and set values in your class from outside. If you declare a property as "atomic" the compiler adds additional code to the getter and the setter so reads and writes to the property are "thread safe", and can be accessed from background threads.
Before ARC, properties also were a very clean way to manage retains and releases. You declared a property as "retain" and the setter was written to retain the object that was passed in. That's less of an issue in ARC, because the system takes care of retains and releases for you.
It is also possible to write a custom getter or setter method that invokes your own code instead of the compiler-written code. You can use that to do things like log information, send notifications about changes, update labels, etc, etc. You simply add a method body to your .m file that has the same method signature as the getter or setter and the compiler uses that method instead of the automatically generated one.
As I said before, the code:
self.foo = #"a string";
is the same as
[self setFoo: #"a string"];
and invokes the setter method. The setter method sets the internal instance variable _foo.
However, the code
_foo = #"a string";
changes the instance variable directly, without invoking the setter. If you do define a property, you should use it instead of the instance variable.
Objective-c use to be simple...and tedious. You would declare instance variables for a class (the orange) and then you would define (usually) 2 methods for each, one so that an external class could set each instance variable to a new value, and one that returned the ivars value so an external object could read it. Aka, you had to write a getter and setter for each ivar. This was two lines of code in the interface and sometimes around 10 lines of code for the implementation file.
Then came properties, declared with #property. There was much rejoicing and drinking in the streets. These single #property lines told the compiler to write those methods for you, including the correct memory management code and even mutex locking code (depending on what you specified when declaring the #property)
Theres a whole lot of history, but nowadays, with automatic reference counting, it really only makes sense to use #properties in your interface, when you want to make an ivar public, and declare your private ivars in your implementation file.
Lastly, not that #property not only tells the compiler to implement your getter and setter, but it also automatically provides an instance variable with the same name, but prefixed with an underscore (this is only if you have implicit synthesizing of properies enabled...more history)
So, thats the difference. #property tells the compiler to write code for you (essentially). What code it actually writes is modified by all the different ways you can declare a #property.
#interface PaneBean : NSObject
#property(nonatomic,copy) NSString *name;
#property(nonatomic,copy) NSString *type;
#property(nonatomic,assign) NSInteger width;
#end
I have a PaneBean as is shown above.
Whether I should use #property(nonatomic,copy) or #property(nonatomic,strong) for my (NSString *) name? What is the difference between them?
And is it right to write 'assign' for NSInteger?
Any help appreciated.Thanks in advance!
'copy' will cause the setter for that property to create a copy of the object, and is otherwise identical to strong. You would use this to make sure that if someone sets your property to a mutable string, then mutates the string, you still have the original value. If the string isn't mutable, Cocoa will silently optimize out the copy operation, which is nice :)
'strong' will keep the property's value alive until it's set to something else. If you want incoming mutable strings to change out from under you (not impossible, but not all that common, a thing to want), then strong would be the right thing to do. Generally strong is more useful for objects that represent something more complex than a simple "value" (i.e. not NSString, NSNumber, NSValue, etc...).
'assign' is the default (and indeed only) possible setting for an integer. Integers can't be retained or copied like objects.
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.In non ARC strong will work like retain
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 sends the copy message the object you set, while strong only retains it (increments the reference count).
For NSString , or in general any inmutable class with known mutable subclasses(NSArray, NSDictionaty, NSSet), copy is preffered to avoid clients setting a mutable instance and modifying it out of the object.
For primitive types(int for example) copy/strong does not make sense and by default assign is used. Is up to you if you want to put it explicitly or not.
Strong indicates composition, while Weak indicates aggregation.
Copy means that a new object is to be created before the contents of the old object are copied into the new object. The owning object, PaneBean in this case, will be composed of the newly created object.
When I'm setting a property with an object that is currently in a retained NSArray, will it only store the pointer (light-weight), or will it copy the contents to the property?
From what I know, it seems like it would only assign the pointer, but I'm not sure.
Also, under what circumstances would using *pointer = *otherPointer or the set methods (setDelegate, for instance) copy the value, instead of just passing the pointer, if any.
Shouldn't it always just pass the pointer address?
It always passes the pointer, as you said. Unless you are specifically adding a de-referencing sign, this will always be the case.
However, when you add a property to a class, and set the setter to copy:
#property (nonatomic, copy) id obj;
When using the dot syntax or the setter, This will be translated to:
_obj = [otherObj copy];
Here, it will depend whether the object in question supports copying itself, or will it fall back to it's super class NSObject or another intermediate class's copy.
Moreover, Collection classes NSDictionary and NSArray do a shallow copy, as in they copy the references to their objects only, so you have two collections pointing to the same set of objects.
A 101 question
Let's say i'm making database of cars
and each car object is defined as:
#import <UIKit/UIKit.h>
#interface Car:NSObject{
NSString *name;
}
#property(nonatomic, retain) NSString *name;
Why is it #property(nonatomic, retain) NSString *name; and not #property(nonatomic, assign) NSString *name;?
I understand that assign will not increment the reference counter as retain will do. But why use retain, since name is a member of the todo object the scope of it is to itself.
No other external function will modify it either.
There's no such thing as the "scope of an object" in Objective-C. Scope rules have nothing to do with an object's lifetime — the retain count is everything.
You usually need to claim ownership of your instance variables. See the Objective-C memory management rules. With a retain property, your property setter claims ownership of the new value and relinquishes ownership of the old one. With an assign property, the surrounding code has to do this, which is just as mess in terms of responsibilities and separation of concerns. The reason you would use an assign property is in a case where you can't retain the value (such as non-object types like BOOL or NSRect) or when retaining it would cause unwanted side effects.
Incidentally, in the case of an NSString, the correct kind of property is usually copy. That way it can't change out from under you if somebody passes in an NSMutableString (which is valid — it is a kind of NSString).
and don't forget to access it via
self.name = something;
because
name = something;
will not care about the generated setter/getter methods but instead assign the value directly.
Without retain there is no guarantee the NSString* you are setting name with will live any longer than the assignment statement itself. By using the retain property for the synthesized setter you're allowing it to tell the memory management system that there is at least one more object interested in keeping the NSString* around.
For those who are looking for it, Apple's documentation on property attributes is here.
The self. in:
self.name = something;
is important! Without it, you are accessing the variable directly and bypassing the setter.
The older style (correct me if I am wrong) would have been:
[self setName:something];
Anyway, this notation was the (vaguely familiar sounding) advice that I really needed when I went looking for proper #properties on NSStrings. Thanks Axel.
After reading so many Articles, SO posts and made demo apps to check Variable property attributes, I decided to put all the attributes information together
atomic //default
nonatomic
strong=retain //default
weak= unsafe_unretained
retain
assign //default
unsafe_unretained
copy
readonly
readwrite //default
so below is the detailed article link where you can find above mentioned all attributes, that will defiantly help you.
Many thanks to all the people who give best answers here!!
Variable property attributes or Modifiers in iOS
retain = strong
it is retained, old value is released and it is assigned
retain specifies the new value should be sent -retain on assignment and the old value sent -release
retain is the same as strong.
apple says if you write retain it will auto converted/work like strong only.
methods like "alloc" include an implicit "retain"
Example:
#property (nonatomic, retain) NSString *name;
#synthesize name;
assign
assign is the default and simply performs a variable assignment
assign is a property attribute that tells the compiler how to synthesize the property's setter implementation
I would use assign for C primitive properties and weak for weak references to Objective-C objects.
Example:
#property (nonatomic, assign) NSString *address;
#synthesize address;
Google's Objective-C Style Guide covers this pretty well:
Setters taking an NSString, should always copy the string it accepts.
Never just retain the string. This avoids the caller changing it under you without your knowledge. Don't assume that because you're accepting an NSString that it's not actually an NSMutableString.
Would it be unfortunate if your class got this string object and it then disappeared out from under it? You know, like the second time your class mentions that object, it's been dealloc'ed by another object?
That's why you want to use the retain setter semantics.