How to use "copy" property in Objective-C? - ios

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.

Related

Custom setter for copy property in objective-c

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]";

Whether I should use #property(nonatomic,copy) or #property(nonatomic,strong) for my (NSString *) attr in An object?

#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.

#syntesize not working in xcode4.6

I am new to ios development and xcode.
Now i was taught that in xcode4.6 programmer doesn't need to use #synthesize statement as the IDE automatically does it for you.
However i don't know why my ide is not setting it then.
#property (nonatomic,strong) NSDictionary *dictionary;
and when i try to set something to it
dictionary = [[NSDictionary alloc]initWithContentsOfFile:resource];
it says undeclared identifier did you mean _dictionary. No i did not mean _dictionary i meant dictionary. So when i manually add synthesize property in implementation everything seems to be working fine.
Can somebody tell me what's going on in here.
The underlying instance variable for that property is in fact _dictionary. That is how auto synthesised properties work.
However you should consider using the accessors to set the property (using self.dictionary = instead). See this answer to "Reason to use ivars vs properties in objective c" for reasons behind this.
Also, consider changing the strong property to copy for classes like NSDictionary, NSArray and NSString to prevent mistakes where a mutable subclass (NSMutableString, NSMutableArray or NSMutableDictionary) is assigned to the property and then mutated.
#synthesize dictionary would have previously been written as #synthesize dictionary = _dictionary where _dictionary would be the variable related with the getters and setters generated by #synthesize.
It is safe to skip the = _variableName since XCode 4, but it will generate a variable matching the name of the synthesised attribute.
dictionary in your case, is only to be used as a setter and a getter, as [self setDictionary:object] or [self dictionary].
If you want to manually assign it a value, then you use _dictionary = object;
Be sure to understand that doing so is not KVC compliant. You will need to inform any observers that the value is about to change.
You forgot self.:
self.dictionary = [[NSDictionary alloc]initWithContentsOfFile:resource];
self.dictionary calls the setter method of the dictionary object, where as dictionary alone attempts to address a variable, either local to the function or an instance variable of the object. In your case you want to address the setter method.
_dictionary is equivalent to self.dictionary in Xcode4.6
This is to make sure that you are accessing the objects of the same current class.

Key-value observation: Can I observe for changes on ALL properties?

Whenever a property on my object is changed or updated I want to change a variable (nonce variable). This nonce is time-based. So everytime a property is updated this nonce gets updated to the current time.
Is there any way to automatically listen for all key changes on my object? Or will I have to manually maintain all keyvalue observers for each property separately?
Many thanks
Did you take a look at the Obj-C runtime functions? See here in the docs. For example, this gives you a list of all the properties in a class Lender. (BTW: I'm not at my Mac, so this is just straight out of the docs):
#interface Lender : NSObject {
float alone;
}
#property float alone;
#end
you can get the list of properties using:
id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
you can then get the name of a property:
const char *property_getName(objc_property_t property)
If you pipe those names back into addObserver:forKeyPath:options:context you should be golden.
Some ideas:
1) you can ask the runtime for the properties and ivars, and their types, and use that information to create and take down observers. Obviously a lot of work if you are doing this for one object.
2) if your properties are "regular", meaning all strong objects, then you can use #dynamic (to prevent setter/getter creation), then use resolveInstanceMethod: or other funky methods from NSObject to catch setMyObject: and myObject calls. You could in essence do what the system does for 'set...' calls, and dynamically get the string of the variable. You could then update/get an ivar, maybe one that has a prefix of "-" or something, and you'd be able to do what your observers would be doing.
3) You could put all the ivars in a "Helper" class, and direct all the setters to it (which could of course message you back), using forwardingTargetForSelector:. I'm using this technique (sort of) in one of my github projects

iOS: Setting properties

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.

Resources