According to this: NSString property: copy or retain?
For NSString/NSMutableString, copy is recommended.
How about NSArray/NSMutableArray?
Since you're asking about NSArray (rather than NSMutableArray), you should use copy. NSArray is immutable, so you don't expect a property of that type to change. But NSMutableArray is a subclass of NSArray, so it's perfectly valid for someone to pass in a NSMutableArray. If you just retain that object, then it may change right under your nose. If you copy rather than retain, then the object won't change.
However, you should be aware that when you copy a container like NSArray, you're copying the container only and not its contents. If the array contains mutable objects, the contents of those objects may change even though the array itself is immutable.
choose copy, unless you have a very specific reason not to, as well as all the supporting code/interface to back that up.
i detailed the rationale and several implications here:
NSMutableString as retain/copy
that example is based on NSStrings, but the same applies for NSArrays.
If it is a problem when the underlying data changes, use copy. In fact, this is what you want most of the time, as changing data behind someone's back is a good source for bugs.
Note that copy will essentially just be a retain for an NSArray. Only when you throw an NSMutableArray in, there is more work involved.
From the link you included, it pretty much comes down to this: NSString property: copy or retain?
If you want to make sure the value of the object won't change during execution, you use the copy attribute, otherwise retain will be fine. Generally, retain will be ok for NSMutableArrays and NSArrays (as well as many other objects) as you are (usually) more interested in the object then in the value it contains. In case of an NSString you are always interested in the value, so you copy it to make sure it won't change.
#jlehr:
It depends if the developer is interested in the actual value or not. Whenever interested in the actual value, use copy (since you don't want the value to change during execution), otherwise retain is fine. From Apple's docs:
It is common practice in Objective-C code to copy value objects—objects that represent attributes. C-type variables can usually be substituted for value objects, but value objects have the advantage of encapsulating convenient utilities for common manipulations. For example, NSString objects are used instead of character pointers because they encapsulate encoding and storage.
Also from Apple's docs, on the topic of value objects:
A value object is in essence an object-oriented wrapper for a simple data element such as a string, number, or date. The common value classes in Cocoa are NSString, NSDate, and NSNumber. Value objects are often attributes of other custom objects you create.
Related
When not compiling with ARC, it is recommended to use copy properties for data types such as NSString. I could not find proper documentation on the use of copy in ARC mode. Can someone tell me what's applicable for ARC?
It is still recommended to copy because you want to avoid something passing a mutable string and then changing it without you knowing. A copy guarantees that the string you have will not change.
Copying and ARC are orthogonal: you make copies of mutable objects to "freeze" their state; ARC keeps track of object's reference count.
NSString objects may or may not be mutable. When you receive an NSString* as a parameter, you cannot be certain that it is immutable unless you check its type (and even then you may get false positives). If your algorithm relies on the string not changing after being set, making a copy is the right thing to do. ARC, on the other hand, will ensure that the object is not released while you are holding a strong reference to it.
It doesn't matter if you're using ARC or non-ARC.
The reasoning behind the copy is so that you can guarantee that your class' internal state can't be modified from outside the implementation.
This could happen if someone passes you an NSMutableString, and then modifies it later. That consideration is independent of the memory management environment.
copy counts as strong. Use:
#property(nonatomic,copy) NSString *name;
https://devforums.apple.com/message/654033#654033
or even:
#property NSString *firstName;
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses.html#//apple_ref/doc/uid/TP40011210-CH3-SW7
I understand that normally you use copy for NSStrings, so that your property stays as the same value as when you assigned it, even when there's an attempt to re-set it somewhere else.
But I am having hard time completely understanding this concept. Doesn't this apply to basically any kind of object (not just NSStrings)?
So my question is, "What kind of properties should I set as 'copy', and why?"
Objects that are simple bits of data, like strings, that won't have references to a ton of other objects in your application are great for copying.
Now you can, of course, retain things like strings instead. This will work fine. But what if you had a mutable string instead, and you modified it. Now every other object that had a reference to that string will see that modification. This may not be what you want. This is one reason copying is "simpler", because any changes to that data is localized to just that bit of code.
On the other hand, lets say you have a instance of a class you wrote for your app. It has references to other objects in your app, it has a ton of it's own strings or other values in it, and it's a complex beast. Now copying this object may not be a good idea. Chances are that if you modify this object then you want the changes to propogate to every object that holds a reference. And even if you did copy it, do you need a shallow copy (a new instance but it's ivars references the same objects) or a deep copy (a new instance containing containing new copies of every ivar)? And the object in question may not even support <NSCopying>, meaning it can't technically be copied at all.
So to sum up:
copy: Objects that are small, atomic bits of data without any internal references to other objects.
retain: Nearly every other kind of object.
Client code can assign an NSMutableString object to an NSString property. If the property was defined as strong or some other non-copy attribute, then if the client later changes the mutable string, the property's value would now be different. By setting the property to be 'copy', a copy of the string value is made and this ensures the value can't change behind your back.
So basically you should use copy whenever the property is for a type that has a mutable counterpart and you want to ensure the value doesn't change on you.
I came to know that, it is better to use copy on #property of NSString than retain due to the problems you can get if you are provided with a NSMutableString. Is the same condition holds true for NSArray , NSDictionary, NSMutableData ?
By problems when retaining I'm assuming you mean that the data may unexpectedly change.
I would consider using copy if the above is unexpected for the circumstances that you are using the string or collection. So you can maintain a known copy of the string, collection or other object that is not going to change without you knowing about it.
However, there may be other reasons to use retain rather than copy on a non-mutable collection or string. You may accept that the contents may change, however use NSArray in the property to show that the object using the container will not modify it itself.
I would think the NSString properties probably want to use copy more so than not. Collections may be different, look at your requirements and see what fits best in your situation.
I have a number of functions similar to the following:
+ (NSArray *)arrayOfSomething
{
NSMutableArray *array = [NSMutableArray array];
// Add objects to the array
return [[array copy] autorelease];
}
My question is about the last line of this method: is it better to return the mutable object and avoid a copy operation, or to return an immutable copy? Are there any good reasons to avoid returning a mutable object where one is not expected?
(I know that it is legal to return a NSMutableArray since it is a subclass of NSArray. My question is whether or not this is a good idea.)
This is a complex topic. I think it's best to refer you to Apple's guidelines on object mutability.
Apple has this to say on the subject of using introspection to determine a returned object's mutability:
To determine whether it can change a received object, the receiver must rely on the formal type of the return value. If it receives, for instance, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership
(my emphasis)
The article goes on to give several very good reasons why you should not use introspection on a returned object to determine if you can mutate it e.g.
You read a property list from a file. When the Foundation framework processes the list it notices that various subsets of the property list are identical, so it creates a set of objects that it shares among all those subsets. Afterwards you look at the created property list objects and decide to mutate one subset. Suddenly, and without being aware of it, you’ve changed the tree in multiple places.
and
You ask NSView for its subviews (subviews method) and it returns an object that is declared to be an NSArray but which could be an NSMutableArray internally. Then you pass that array to some other code that, through introspection, determines it to be mutable and changes it. By changing this array, the code is mutating NSView’s internal data structures.
Given the above, it is perfectly acceptable for you to return the mutable array in your example (provided of course, you never mutate it yourself after having returned it, because then you would be breaking the contract).
Having said that, almost nobody has read that section of the Cocoa Objects Guide, so defensive programming would call for you to make an immutable copy and return that unless performance profiling shows that it is a problem to do that.
Short Answer: Don't do it
Long Answer: It depends. If the array is getting changed while being used by someone who expects it be static, you can cause some baffling errors that would be a pain to track down. It would be better to just do the copy/autorelease like you've done and only come back and revisit the return type of that method if it turns out that there is a significant performance hit.
In response to the comments, I think it's unlikely that returning a mutable array would cause any trouble, but, if it does cause trouble, it could be difficult to track down exactly what the issue is. If making a copy of the mutable array turns out to be a big performance hit, it will be very easy to determine what's causing the problem. You have a choice between two very unlikely issues, one that's easy to solve, one that's very difficult.
A question that has pondered me for the last while. I am primarily a .net developer who dabbles in Objective-C for iPhone and Mac.
How do you go about sending "datasets" between methods in objective-c. For example in C# you can populate a custom class with data and pass it around in a List of type custom class. EG if you had a customer class you would just do something like:
List<Customer> customers = DataLayer.GetAllCustomers();
The only way I can see how this could be done in obj-c would be to populate an NSArray with custom objects? Is this an efficient way to do things? Any other recommendations? I am using sqlite as the database/data I want to return.
You're on the right track.
Cocoa's collection classes — which all have mutable an immutable variants — are:
NSArray: ordered, can contain an object multiple times
NSDictionary: unordered, mapping from keys to values, keys are copied
NSSet: unordered, can contain an object only once
NSCountedSet: unordered, can contain an object multiple times
The immutable variants help a lot with efficiency. The standard pattern for accessors of classes that have mutable variants is to copy rather than retain. This is codified in the #property mechanism, by using the copy attribute on the property:
// Department.h
#interface Department : NSObject
#property (readwrite, copy) NSSet *employees;
#end
This means that if you pass a mutable array to something that takes an array, it will be copied, and if you pass that to something else, it will be copied again. The trick is though that "copying" an immutable object really just retains it, so you only take a hit for that first copy. You probably want to make a copy that first time anyway so you don't pass a mutable array to something else, then mutate it behind the back of whatever you passed it to.
For Cocoa on Mac OS X, I'd also strongly encourage you to take a look at Core Data. It's an alternative to the "data set" pattern you might be used to from .NET/ADO/etc. With Core Data, you don't "get all customers" and then pass that collection around. Instead you query for the customers you care about, and as you traverse relationships of the objects you've queried for, other objects will be pulled in for you automatically.
Core Data also gets you features like visual modeling of your entities, automatic generation of property getters & setters, fine-grained control over migration from one schema version to another, and so on.