This is probably a silly question but I have been thinking it over for a while with no obvious answer.
I have a small app that I have been working on and am having a problem with my NSMutableArray instance variable. It was always (null) until I added an [[NSMutableArray alloc]init] to the viewDidLoad.
I am pretty new to the Objective C world so I am trying to get an understanding of this issue. I was under the impression that with I instantiated my class the instance variables were all alloc'd. When I add items to the array without the alloc/init it remains (null) with a retain count of 0.
The array in question was declared as a (retain) property.
I can add code if this isn't clear.
Any instance variables that are objects are actually just pointers that are initialized to nil (0). That is why the item isn't retained and added to the array, since messages to nil objects return nil/0.
You need to alloc and init the object in your class's init, and then release it in the dealloc.
The retain/assign/copy qualifiers on the property declaration are about how the memory for the property value is managed in the getters and setters that the compiler synthesizes for you. (The documentation discusses them in detail, and gives example code for each kind.)
That's completely orthogonal to whether your instance variables are initialized for you or not. Declaring an ivar is just reserving storage for the value; for Objective-C classes, that's a pointer to an instance. The runtime will initialize those ivars to zero for you, but you're still responsible for creating the objects you want to store there. (The same is true in similar languages like Java or C#: declaring an Array instance variable just gives you space for a reference, it doesn't create the array for you.)
Related
I was just working on my application where I needed to set an instance variable of NSMutableData a value. Now I also created a property for my instance variable which means that my program automatically allocates it etc, right? But then I assigned it a value but it was not taking it but staying null. I then manually allocated it and then it suddenly accepted the value. So now my question is what is the need for properties and why do I have to manually allocate my instance variable although I have a property set up for it?
Thanks in advance!
edit: my code:
in my .h file I have
#interface FirstScreen : UIViewController{
NSMutableData* fetchedData;
}
#property(nonatomic, retain)NSMutableData*fetchedData;
in my .m file I have:
-(void) connectionDidFinishLoading:(NSURLConnection *)connection{
NSString* fetchedDataString= [[NSString alloc]initWithData:fetchedData encoding:NSUTF8StringEncoding];
}
Now if I do not implement:
-(void)viewDidLoad{
self.fetchedData=[[NSMUtableData alloc]init];
}
fetchedDataString does not have any value. However if it is allocated it has a value. I am confuces when to allocate instance variables and when not to.
It doesn't allocate. All properties do for you is define the instance variable & implement accessor methods.
I'm assuming by "assigning a value" you mean trying to set the contents of the NSMutableData object you thought had been allocated for you.
Now I also created a property for my instance variable which means
that my program automatically allocates it etc, right?
Wrong. If you synthesize accessors for the property, an ivar will also be created for it if you haven't created one. But your property is just a pointer... it doesn't point to anything until you create an object for it to point to, and set it:
self.fetchedData = [[NSMutableData alloc] init];
That's C. What you're saying is true for every single variable, whether it's local or an instance variable. It's one thing to declare storage for a variable (that's all you're doing by declaring a property). It's another to give it a value. This declaration in code:
NSMutableArray* arr;
...does not cause arr to take on any particular value (under ARC it's nil; prior to ARC it could be anything at all). It is certainly not an empty mutable array! But that's exactly analogous to what you're doing when you declare a property.
If this is the first value the variable is to adopt, that's called initializing. You might say in code:
NSMutableArray* arr = [NSMutableArray array];
But you can't do that in a property declaration, so you have to initialize at some later time while the code is running. A typical approach is to do this in your designated initializer, so that no matter what happens later there will be an actual array at this address, from very early on.
I've written a book on this topic (iOS programming), and the chapter dealing with the issue you're having is free to read online:
http://www.apeth.com/iOSBook/ch03.html
I'm a bit confused as to whether NSStrings should ever be retained and synthesized. I have a NSString value as an instance variable, and am retaining and synthesizing it. But I am assigning it different values such as:
self.value = #"VALUE";
....
self.value = #"DIFFERENT_VALUE";
I'm not actually calling alloc anytime. Do I need to retain and synthesize this variable then?
You can think of on-the-fly strings as autoreleased in terms of how you use them, although in reality they will probably stay around as fixed values... because you are using the accessors they will automatically get copied or retained (however you marked the accessor) and so you do need to release them in dealloc.
As for the need to #synthesize, remember all that is doing for you is actually creating the get/set methods that take the variable and place it in your iVar. So not matter what you either need to #synethsize a property OR create the get/methods yourself - usually far better just to use #sythesize.
You should as you'll never know how you are going to change the use of the code in the future. Change the code to use dynamically created strings, and it will break if don't follow the rules.
Also note that the best practice for NSString is to set it to copy instead of retain. The reason is simple, this prevents the string from being changed under your feet.
See NSString property: copy or retain? for more details.
If you have never alloc'ed them, you usually don't need to retain, but if they are instance variables in your objects, they are probably marked as retain or copy so at your object's dealloc method you should release these objects if there is a value on it.
The title says everything!
In Objective-C, what's the difference between self.propertyName vs. propertyName?
self.propertyName is sending the object a message, asking it for the value of propertyName, which means it may go through a getter/setter, etc. propertyName is directly accessing the ivar, bypassing any getter/setter. Here's an article going into it in rather more detail.
self.propertyName increse the retain count by one if you have specified the propertyName as retain in property declaration
propertyName will not increase the retain count an could lead to the crash of application.
e. g. ,
#property (nonatomic,retain) NSString* propertyName;
lets say you have nameProperty NSString object.
Below increase the retain count by 1 and you could use self.propertyName and call release.
self.propertyName = nameProperty;
[nameProperty release];
Below does'nt increase the retain count so if you use propertyName in your application it will result in crashing of your application.
propertyName = nameProperty;
[nameProperty release];
Any further use of propertyName will result in crash.
self. runs through your likely synthesized accessor methods if you are using properties
ie self.propertyName = newName is the same as [self setPropertyName:newName]
This becomes important for memory management as propertyName = newName would cause you to loose reference to the previous contents of propertyName
If you call self, you can be sure you're calling the class/object that owns the property.
You may find this useful too:
Assigning to self in Objective-C
dot notation is turned into a method call by the compiler. This means that there is extra work at run time for executing this method call, like copying something from and to the stack memory and executing a jump in machine code.
the instance variable by itself is faster because it is essentially just a memory address or scalar value (like int).
One would prefer the self.something notation when you want or need an extra layer to do something. Like retain an object that is passed in or lazily instantiate an object on the first time you need it.
Setting the value of the property does just that - it sets the value of the property directly without going through any accessors or synthesized accessors.
By calling the accessor through self you are going through the accessors. For properties that have been declared with retain or copy it will retain or copy the value that is passed in. For non objecte properties, the usual declaration is assign which means that there is no memory management applied to those iVars.
You see both types of calls - but it is preferred to use the direct method in initialisers and the dealloc method, because calls to self are discouraged in these methods.
If you have declared and synthesized the property, the call to self also generates the KVO notifications for changes in that variable. This saves you having to write the willChangeValueForKey: and didChangeValueForKey: methods.
In my iPhone development book, I'm seeing some strange coding examples in regard to what an array does when objects are added to the array and when the whole array is released. One code example has the following properties on an instance array:
#property (nonatomic, retain) NSMutableArray* myArray;
The author adds an object to the array and, immediately after, releases his pointer to the object. Won't the array cell now point to garbage data? Unless, behind the scenes, the array cell retains the object when added.
SomeObject* someObject = [[SomeObject alloc] init];
[self.myArray addObject:someObject];
[someObject release];
The author also releases the the pointer to the array without first going through each array cell and releasing the individual objects. This is a memory leak unless, behind the scenes, each cell is sent a release message;.
- (void)viewDidUnload {
self.myArray = nil;
[super viewDidUnload];
}
Unless, behind the scenes, the array cell retains the object when added.
Yes, this happens.
... unless, behind the scenes, each cell is sent a release message.
This also happens.
You have answered your own question.
Here is a quote from Collections Programming Topics:
And when you add an object to an
NSMutableArray object, the object
isn’t copied, (unless you pass YES as
the argument to
initWithArray:copyItems:). Rather, an
object is added directly to an array.
In a managed memory environment, an
object receives a retain message when
it’s added; in a garbage collected
environment, it is strongly
referenced. When an array is
deallocated in a managed memory
environment, each element is sent a
release message.
Unlike in C or C++ where you constantly worry about whether to delete an object or not for the fear of it is still being used somewhere else, Objective-C (or rather it's actually Cocoa SDK) uses the mechanism of reference counting or ownership.
You might already know how it works but you need to also know that in Cocoa, if an object A needs to use another object B it should own (i.e. retain) it. That object A should not rely on some other object C already retained B, because it cannot know when C releases it. So in your case, since NSArray needs to use all objects added to it latter during its lifetime, it needs to retain all the objects. And because of that, when the array is de-alloc-ed, it needs to release them.
This concept of "you need to retain what you want to use latter" is very important when you are dealing of lots of objects.
There are several places in apple development guides that explain that is a good practice to take the ownership of an object (send a retain message) if you plan to use it later. You should do it so that the object is not destroyed while you still might need to access it.
Considering that, you were right assuming that the NSArray retains the object when it is added to the collection, as it still might try to access it afterwards.
You can check the Memory Management Programming Guide
When you add an object to a collection such as an array, dictionary, or set, the collection takes ownership of it.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW3
or the Collections Programming Topics for more details
... In a managed memory environment, an object receives a retain message when it’s added.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Arrays.html#//apple_ref/doc/uid/20000132-SW1
You're right on the first point. When an object is added to an array, the array retains the object. Thus, for an object that has been previously retained, it is necessary to release it after adding it to the array or you can end up with a memory leak.
Likewise, when an object is removed
from an array, the array releases the
object. So, if you want to keep it,
you'll need to retain it.
When an array is released, as you
surmised, the array will release all
the objects it contains. Thus,
releasing each object individually is
not necessary and, in fact, would
raise an exception.
Finally, regarding the line of code
in -viewDidUnload that you quoted:
self.myArray = nil;
This works properly with regard to memory management as long as the myArray property was synthesized as follows:
#synthesize myArray;
Synthesizing creates a setter that effectively does the following:
- (void)setMyArray(NSMutableArray *)anArray
{
if (![myArray isEqual:anArray]) {
[myArray release];
myArray = anArray;
[myArray retain];
}
}
So, when called, the above setter will first release the old array (as long as it's not the same object as the new array.) Then, it will retain the new array, which in this case is nil. Note that retaining nil will just do nothing, and won't trigger an error.
Of course, if you don't synthesize the myArray property, or if you override the setter, you will have memory problems unless you also release the old value & retain the new in your setter.
I noticed that I rarely use properties, due to the fact that I rarely need to access my object's variables outside my class ;)
So I usually do :
NSMutableArray *myArray; // not a property !
My question is : even if i don't declare myArray as a property, does iphone make a retain anyway if I do
myArray = arrayPassedToMe;
I think so but I just wanted to confirm ;)
Any thoughts welcome !
Gotye
If you do not declare a property with 'retain' then no retain call will be made. It is generally preferable to use the property accessors (for all cases, it makes memory management much simpler), however you can perform a manual retain as such:
myArray = [otherArray retain];
Just to add to Kevin's answer, in this case you also need to make sure that any existing object at which myArray is currently pointing is freed before you assign new value to it, which means:
[myArray release];
myArray = [otherArray retain];
When you access your class variables via declared properties, all this stuff with retaining/releasing memory is done for you automatically, making your life much easier.