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.
Related
in interview has a question "Could NSMutableArray property use copy why and why not " I have searched the answer but I want to see the auto generate's getter setter code how can I do?
You cannot see the Obj-C code for the setter only the assembler. To do this first select the source file containing the property in Xcode and then choose the menu item Produce > Perform Action > Assemble "File.m". This will open up a window containing the assembly code. Search for setPropertyName: where PropertyName is the capitalised name of your property.
This will show you the setter calls _objc_setProperty_nonatomic_copy or _objc_setProperty_atomic_copy. To see the code for those you will need to use the debugger and step into them. They essentially just call copyWithZone:.
More important is the reason behind the interview question. Either simple experimentation, or digging through the assembler as above, shows that the copy property attribute always does a copy and not a mutableCopy. So the declaration:
#property (nonatomic, copy) NSMutableArray *shouldBeInvalid;
would in an ideal world generate a compiler error. If you assign a mutable array value to the property:
self.shouldBeInvalid = #[ #24 ].mutableCopy;
then due to the copy the value actually assigned is an immutable array (NSArray), contradicting the NSMutableArray declared type. Trying to use the property value later as a mutable array:
[self.shouldBeInvalid addObject:#42];
will produce a runtime error as the property's value is an immutable object contrary to its declared type...
You'll also find that the compiler happily allows you to assign an immutable array to the property:
self.shouldBeInvalid = #[ #24 ];
without so much as a warning.
What the interviewer was probably seeking was for you to explain that for a property copy + mutable type makes no sense in Objective-C as the copy will produce an immutable object value. However a property with copy and an immutable object type (NSArray, NSDictionary, etc.) does make sense so that if a mutable object value is assigned an immutable copy of it is made, which prevents the property's value changing unexpectedly, e.g.:
#property (nonatomic) NSArray *shouldHaveCopy;
NSMutableArray *sample = #[ #"oops" ].mutableCopy;
self.shouldHaveCopy = sample;
[sample addObject:#"'immutable' property changed"];
// self.shouldHaveCopy now references a two element array despite
// its type being `NSArray`
So the general rules are:
A property intended to have a mutable object value (NSMutableDictionary et al) should never specify copy; and
A property intended to have an immutable object value, when there is a corresponding mutable object subclass (e.g. NSArray has NSMutableArray etc.), should always specify copy.
HTH
You can‘t really see the source code. You could step into it in Xcode‘s debugger though, and see an assembler version of it, which is reasonably readable if you know any platform‘s assembler or are good at guessing abbreviations for english words.
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.
If I declare a public property as :
#property (retain) NSString * name;
Then how does the compiler implicitly implement this? I have read that the retain gains ownership over the instance variable "_name". I have also read that "retain" message increases the reference count of the object.
So each time I call the setter for "name" property in the above example, will it increase the reference count?
So after this,
object.name=#"name1";
object.name=#"name2";
Will the reference count be 2?
To answer your specific question:
object.name = #"name1";
name now holds a strong reference to the "name1" string instance.
object.name = #"name2";
name now holds a strong reference to the "name2" string instance. No object holds a reference to the "name1" instance, and a release statement will be inserted by the compiler for "name1". (in practice, the first statement will likely be optimized away entirely).
According to Blamdarot in this answer:
"retain" is needed when the attribute is a pointer to an object. The setter generated by #synthesize will retain (aka add a retain count) the object. You will need to release the object when you are finished with it.
#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.
I'm new to Objective C. I have basic knowledge in C, including the concept of pointers. I have two basic questions:
Can someone explain the difference between assign,copy, and retain with some analogy?
How do you handle a function which returns pointer variable, and how do you perform messaging through a return pointer?
Updated Answer for Changed Documentation
The information is now spread across several guides in the documentation. Here's a list of required reading:
Cocoa Core Competencies: Declared property
Programming with Objective-C: Encapsulating Data
Transitioning to ARC Release Notes
Advanced Memory Management Programming Guide
Objective-C Runtime Programming Guide: Declared Properties
The answer to this question now depends entirely on whether you're using an ARC-managed application (the modern default for new projects) or forcing manual memory management.
Assign vs. Weak - Use assign to set a property's pointer to the address of the object without retaining it or otherwise curating it; use weak to have the property point to nil automatically if the object assigned to it is deallocated. In most cases you'll want to use weak so you're not trying to access a deallocated object (illegal access of a memory address - "EXC_BAD_ACCESS") if you don't perform proper cleanup.
Retain vs. Copy - Declared properties use retain by default (so you can simply omit it altogether) and will manage the object's reference count automatically whether another object is assigned to the property or it's set to nil; Use copy to automatically send the newly-assigned object a -copy message (which will create a copy of the passed object and assign that copy to the property instead - useful (even required) in some situations where the assigned object might be modified after being set as a property of some other object (which would mean that modification/mutation would apply to the property as well).
The Memory Management Programming Guide from the iOS Reference Library has basics of assign, copy, and retain with analogies and examples.
copy
Makes a copy of an object, and returns it with retain count of 1.
If you copy an object, you own the copy. This applies to any method that contains the word copy where “copy” refers to the object being returned.
retain Increases the retain count of an object by 1. Takes ownership of
an object.
release Decreases the retain count of an object by 1. Relinquishes
ownership of an object.
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"First",#"Second", nil];
NSMutableArray *copiedArray = [array mutableCopy];
NSMutableArray *retainedArray = [array retain];
[retainedArray addObject:#"Retained Third"];
[copiedArray addObject:#"Copied Third"];
NSLog(#"array = %#",array);
NSLog(#"Retained Array = %#",retainedArray);
NSLog(#"Copied Array = %#",copiedArray);
array = (
First,
Second,
"Retained Third"
)
Retained Array = (
First,
Second,
"Retained Third"
)
Copied Array = (
First,
Second,
"Copied Third"
)
assign
assign is a default property attribute
assign is a property attribute tells the compiler how to synthesize the property’s setter implementation
copy:
copy is required when the object is mutable
copy returns an object which you must explicitly release (e.g., in dealloc) in non-garbage collected environments
you need to release the object when finished with it because you are retaining the copy
retain:
specifies the new value should be sent “-retain” on assignment and the old value sent “-release”
if you write retain it will auto work like strong
Methods like “alloc” include an implicit “retain”