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.
Related
I need to do an operation just once when my app is launched the first time. I fit success no need to repeat during subsequent launches.
I am using the standard approach of using a property and setting it to YES the first time app is launched and initialization code succeeds.
I have a few Qs that will help me improve my Objective-C understanding and hence would greatly appreciate the experts inputs.
I am assuming I need to set the property attribute to strong since the memory associated with the variable may be released if it is set to weak. Is this correct?
Setting it to strong is preventing me from using BOOL type (the error indicated I need to use an object)
To workaround, the property type is set to NSNumber and I am setting it to #(YES) after routine completes and comparing it against #(YES) to see if initialization needs to be done at app launch.
IS the above approach/understanding correct? If no, I'd appreciate pointers to what is wrong. Also, even if above will work, but there is a more elegant way to do what I'm trying to do, please do let me know.
I am assuming I need to set the property attribute to strong since the memory associated with the variable may be released if it is set to weak. Is this correct?
Sorry, NO.
An automatic property (one where you do not write your own setter and getter methods) lifetime & memory behaviour is the same as for instance variables. So:
The lifetime of the property is the same as the object instance it belongs to - the storage for the property is created as part of creating the object instance, and it is destroyed as part of destroying the instance.
For properties with primitive type; e.g. int, double, BOOL, NSInteger etc.; the value is stored directly in the property and there is no other memory management required.
For properties of object reference type; e.g. NSArray *, NSNumber *, etc.; the value stored in the property is a reference to an object. In this case the property may be marked as strong, weak, etc. so that ARC knows how to manage the lifetime of the referenced object (not the lifetime of the property).
So in your case with a BOOL property you do not need strong, weak, etc. - they would be meaningless for such a property. You do not convert your property to NSNumber * just so you can make it strong, there is no need to do this.
I am using the standard approach of using a property and setting it to YES the first time app is launched and initialization code succeeds
For your particular application this is not the standard approach, what you need is a value which will persist between application launches, and for that you can user NSUserDefaults. In particular you need the methods boolForKey: to retrieve the current value, and setBool:forKey: to set the value.
When you first run your application you will (obviously!) not yet have written any value to NSUserDefaults. In this situation, where a value for a key has not yet been written, the method boolForKey: will return NO. So all your application needs to do to run code once on the first run is to read the key you will use for this, say #"firstRunDone", and if the result is NO to execute the first-run code and then set the key value to YES.
HTH
You're right about using strong modifier. strong only applies to NSObject-derived types (ie types derived from NSObject, which implies it has to be a class type), so you are correct about using NSNumber instead of BOOL.
However, if you need to run only the first time the app launches, you need to store it in a more persitent place, e.g. NSUserDefaults; an ivar/property will be gone as soon as the app is terminated, and takes default value when the app launches again. NSUserDefaults also supports primitive BOOL type, no need to worry about memory policy.
The strong and weak property attributes are to do with Automatic Reference Counting within Objective-C, i.e., iOS uses this to know when an object is still being used and should be kept in memory. The "strong" attribute will increment the reference count of the object in question, preventing the memory associated with the variable being released; so yes you are correct when you say that you need to set the property to strong.
With weak properties, the referenced object may be released while the property holds the reference. This is a helpful explanation of memory leaks & properties etc: http://www.quora.com/What-is-the-difference-between-strong-retain-nonatomic-etc-in-the-Objective-C-iOS-property
To use the BOOL type, you do indeed need to use an object. BOOL is an intrinsic type and so cannot have an explicit value; there needs to be something there to be true or false (or yes or no, in this case).
I hope this has helped your understanding a bit :) There are other similar SO posts dealing with BOOL properties; they might be helpful too. Good luck!
I want to ask which is faster:
Making a new class object using alloc+init or making a Copy of the existing class object?
edited:
I was reading the prototype pattern and I got this query. In prototype pattern, we make a clone or copy of the existing object.
So in which case copy is faster than alloc?
The answer, of course, is it depends on what kind of object you're dealing with. For immutable objects such as NSString, calling -copy really only retains the original object. On the other hand, one can guess that copying an instance of NSMutableString involves both creating a new object and copying the data from the original object, and in such cases copying would obviously take longer than simply creating a new, empty object.
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.
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.
in my app i need to pass a NSMutableString from one class to another so i put it extern.The problem is that when i run the app, the class does only access the string once, the second time the app crashes !! Obviously the NSMutablString becames nil after the first access. So i tried to figure out something: i converted the string into a C char. Well this time the app doesn't crash, but.. the value of the char changes everytime i call it !!
Am really confused: Please i need to know
Is there any way to maintain the value of the NSMutablString so it would be available everytime a class calls it ?
What causes the changing in the char's value ?
Thanks for any help
It sounds like you're doing some weird thing, really.
If you want to pass the NSMutableString instance from one object (source) to another (target), you should either assign it to the target object's property, or pass it via some method call.
The target object should retain this instance (either explicitly, or using 'retain' flag of the property), to ensure the instance is valid regardless of what the source object does. The target object should also release it, when it is no longer needed, otherwise you'd introduce a memory leak.
It is not really obvious, that "NSMutableString (pointer) becomes nil". Any invalid reference can lead to a crash when dereferenced, not only nil. Actually, my guess is that you're trying to access a deleted object.
I guess you've used [NSMutableString cStringUsingEncoding:] or similar method to get char pointer. Keep in mind that the pointer returned is valid for a limited time, check the docs.
Anyway, this is all pretty basic stuff. You should read Memory Management Progamming Guide and make sure you understand everything. It's simply essential to develop a stable Objective-C code.