Where should I alloc/init my ivar? - iphone

If I know that I'm going to use the ivar should I alloc/init it in viewDidLoad like:
if (allPeople_ == nil)
self.allPeople = [NSArray arrayWithArray:[[selectedObject people] allObjects]];
or should I create a getter method and alloc/init in there:
- (Group *)allPeople {
if (allPeople_ != nil)
return allPeople_;
allPeople_ = [NSArray arrayWithArray:[[selectedObject people] allObjects]];
return allPeople_;
}
I'm assuming the getter method, with the if-statement, is for lazy-loading, which in my case I wouldn't need to do because I'm definitely using self.allPeople throughout my code.
Extra Question:
If I use the getter method do I actually have to do it this way?
allPeople_ = [[NSArray arrayWithArray:[[selectedObject people] allObjects]] retain];

I would initialize it whenever you are going to use it.
As for the second question, it depends on how your property is declared if it is declared as retain, and you set it like this:
self.allPeople =
you will not have to send it a retain message, because the synthetized setter will take care of that for you.
Do notice self.allPeople is different than just allPeople, if you don't use self you are not accessing it thru the setter, you are accesing the ivar directly and therefore it won't receieve a retain message.

You might try to make your NSArray an NSMutableArray that way you can alloc init it in your init call. Use property declarations to synthesize your getters and setters. As for putting the people in your array, you can add them to the mutable array every time one is selected

Related

Why can I not initialise my variable without using self

I have the following variable defined:
#property (nonatomic, retain) NSMutableArray *arraySpeechSentences;
And I am trying to initialise it in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
[speechSentences release];
When I try to call [arraySpeechSentences count] the application crashes. However, if I set the variable in the following way:
// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
self.arraySpeechSentences = speechSentences;
[speechSentences release];
I can call [arraySpeechSentences count] perfectly fine. I was under the impression that if you use self. it simply checks to see if variable is already set, and if so it will release the object before assigning it the new value. Have I got this wrong, and if so when should I be using self. to set values?
Thanks for any help,
Elliott
Using a setter (like self.foo = ... or [self setFoo:...]) does release the old value but it also retains the new value, which is needed in the example you give.
The issue is that you're alloc and init'ing your array, and then releasing it. This indicates you no longer need it. So, you should either use the setter (usually preferable) or don't release your array.
If you're not using ARC, you should type
arraySpeechSentences = [speechSentences retain];
because you're accessing the instance variable directly, which means the value of the instance variable arraySpeechSentences will be the address of the speechSentence object, which you just released, so which is an invalid pointer. The semantic you declared in the property doesn't have an effect on the instance variable itself.
When you type self.arraySpeechSentences, you're actually using a shortcut for the setter [self setArraySpeechSentences:speechSentences], which actually retains the value passed as parameter (if you synthesized the property, it is retained because you specified retain in the property declaration; if you wrote the accessor yourself, it is your job to ensure you retained the value).
I'll try to give a detail answer for this.
First when you use #property/#synthesize directive you create getter and setter methods around a variable.
In your case, the variable is called arraySpeechSentences (the compiler will create the variable for you) and you can access these methods (setters and getters) with self..
self.arraySpeechSentences = // something
is the same as
[self setArraySpeechSentences:something]; // setter
And
NSMutableArray* something = self.arraySpeechSentences;
is equal to
NSMutableArray* something = [self arraySpeechSentences]; // getter
In the first snippet of code
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
arraySpeechSentences points to the same object speechSentences points to. But when you do [speechSentences release] you dealloc that object and now arraySpeechSentences is a dangling pointer. You receive a message sent to a deallocated instance I suppose. Try to enable Zombie to see it.
Speaking in terms of retain count, the array has a retain count of 1 when you do alloc-init.
But when you release it, the retain count goes to zero, the object doesn't exist anymore and you have a crash when you try to access arraySpeechSentences.
Instead, when you deal with properties, the policy applied to a variable is important. Since the property use a retain policy, when you set an object
self.arraySpeechSentences = // something
the retain count for the referenced object is increased. Under the hood, saying self.arraySpeechSentences = // something is equal to call the setter like
- (void)setArraySpeechSentences:(NSMutableArray*)newValue
{
// pseudo code here...
if(newValue != arraySpeechSentences) {
[arraySpeechSentences release];
arraySpeechSentences = [newValue retain];
}
}
The second snippet work since the retain count for your object is one when you do alloc-init, becomes two when you call self.arraySpeechSentences = and returns to one when you do the release. This time, the object is maintained alive since it has a retain count of 1.
If you have a property with a retain or copy policy, don't forget to release the object in dealloc like, otherwise you can have leaks.
- (void)dealloc
{
[arraySpeechSentences release];
[super dealloc];
}
To understand how Memory works I suggest to read MemoryManagement Apple doc.
P.S. Starting from iOS 5 there is a new compiler feature, called ARC (Automatic Reference Counting), that allows you to forget about retain/release calls. In addition, since it forces you to think in terms of object graphs, I suggest you to take a look into.
Hope that helps.

property assign

If I have one property like this, what is the diference of assign the value of the property of the first mode and the second mode?
#interface Prueba : NSObject{
CustomeClass *_cclass;
}
#property(nonatomic, retain)CustomeClass *cclass;
#end
#implementation Prueba
#synthesize cclass = _cclass
- (void)config{
// 1 This
self.cclass = [[CustomeClass alloc] init];
// 2 This or
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];
}
#end
:/
Your first example gives you an object with a retain count of two (wrong), whereas your second example gives you an object with retain count of one (right). The second method is preferred in non-ARC projects. Alternatively, you could also do either set the ivar yourself (which I don't like because you're not using the setter):
_cclass = [[CustomeClass alloc] init];
or use the setter as your examples do, but do an autorelease (which I don't like because you shouldn't defer your releases unless you have to):
self.cclass = [[[CustomeClass alloc] init] autorelease];
In your non-ARC project, your original second example is best (using a pointer, using your property's setter, then releasing your pointer), because for KVO you want to get in the habit of using the setter:
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];
There is no difference in the result except that in the second method you create an additional pointer. In both versions self.cclass will hold your object just fine.
The problem is that when you only release the object in your second mode, in the first mode you'll have a memory leak. Since the retainCount of an object is +1 when you allocate it, you assign a +1 object through your setter. This means, that you actually bump up the retainCount again. Now if you don't release the object after assigning it to your property, once it gets released from there the retainCount will only be reduced by 1. Thus letting an object with a retainCount of +1 float around in the memory, lost forever.
But because you are already asking about a better version, I want to introduce lazy instantiation to you. What you can do, is that you overwrite the getter method of the property in question and check if it has been allocated yet. If not, you allocate it inside your getter method and then return it. It would look something like this:
- (CustomeClass*) cclass
{
if(!_cclass)
{
_cclass = [[CustomeClass alloc] init];
}
return _cclass;
}
With this method you assign a +1 retained object to an internal variable, thus bypassing the setter and not increasing the retainCount. Also it's memory friendly, because you object only gets instantiated when you really need it. Now when you set your property to nil or some new object, the old object will be properly deallocated.
EDIT:
In response to Robert Ryan's comment I want to add the following:
This does not break KVO, or interfere with the assigned qualifies for your properties. If your property is marked as assign or weak, then lazy instantiation doesn't really make sense. If it's marked as retain or strong this way of instantiating an object is perfectly fine, especially when it is a property which you would assign anyway inside a config method.
Regarding KVO: the value which is assigned inside the getter can be seen as the initial/default value, so KVO still works. It will trigger when you use the setter to assign something else to the property. You wouldn't want KVO to trigger because of a default value, would you?

Question about autorelease object in Objective-C

I have an instance variable called users defined as NSMutableArray.
I use that variable for fill an UITableView.
In viewDidLoad I initialize it with:
users = [[MySingleton sharedClass] getUsers];
This is the getUsers method:
- (NSMutableArray *)getUsers
{
...
NSMutableArray *listArray = [[NSMutableArray alloc] init];
for (NSDictionary *dict in jsonObject) {
...
[listArray addObject:element];
...
}
return listArray;
}
In this way all it works fine. The problem is when I set listArray as autoreleased object.
NSMutableArray *listArray = [[[NSMutableArray alloc] init] autorelease];
or
return [listArray autorelease];
Sometimes the app crash with EXC_BAD_ACCESS.
Why this? Isn't correct set autorelease listArray?
Assuming that users in users = [[MySingleton sharedClass] getUsers] is an instance variable, you're forgetting to take ownership of the array. When you want to claim ownership of an object (such as this array), you need to send it retain to tell it you want it to stick around. And when you're finished with it, you need to send it release to tell it so. Setters handle this for you, so it's generally a good idea to use setters outside of init and dealloc methods. So assuming you have a setter for users, you could do one of these:
self.users = [[MySingleton sharedClass] getUsers];
/* OR */
users = [[[MySingleton sharedClass] getUsers] retain];
The first way is usually better, but you don't want to call setters in init… or dealloc methods because they might have side effects that are undesirable there. Since you're not in one of those methods here, you can just use the first.
You have created and assigned an autoreleased object to user. By specifying autorelease you are saying that system could free it. So when it reaches the end of autorelease pool its removed from memory. That is why when you try to access it late it crashes. So if you need it to be global then you need to retain it.

Difference between self.instanceVar = X and instanceVar = X in Obj-c

For the following two lines in an obj-c class:
self.instanceVar = X
instanceVar = X
Is the only difference that the 'self' version calls the synthesized 'setter', whereas the latter simply sets the instanceVar and doesn't go through the setter?
Thanks
Yes. The implication of this is that the synthesized getter will wrap additional code depending on how the property is specified - so use of assign / retain / copy along with nonatomic / atomic change the behaviour.
Imagine the following:
#property( retain ) NSString * myprop;
If you set it by self.myprop, the NSString instance will be retained.
If you set directly the instance variable, this will not be the case.
So always use the self., unless you're absolutely sure...
This is an excellent question and understanding the difference between setting a variable through its accessor rather than directly assigning it is very important.
Here's what happens: when you declare a #property (nonatomic, retain) NSString *variable in the header, you add a property to your object. Simple enough. Calling #synthesize does the following thing: it generates two methods in your class, setVariable: and getVariable. Of course, if you name your property "name", the methods will be setName: and getName.
Now, it is important for you to understand what happens in the setVariable: method. The method is declared something like this:
- (void)setVariable:(NSString *)theVariable {
if (variable != nil) {
[variable release];
}
// variable is the class member,
// theVariable is the object that was sent by the method parameter
variable = [theVariable retain];
}
When you call self.variable = #"test"; you will actually call [self setVariable:#"test"] which is exactly the method that was generated by the #synthesize call!
When you call variable = #"test"; you do just that - you assign a string to a variable, without retaining it or anything.
If you were to call self.variable = nil the current value of the variable would be released and variable will be assigned to nil, but if you were to call variable = nil you would just ditch the reference to the previously assigned value (object). Therefore, if you would be calling
self.variable = #"test";
// wrong, do not do this in this case
variable = nil;
you would be be generating a memory leak because the #"test" object that was assigned to variable and retained through its accessor is never going to be released. Why's that? Because the setter (setVariable:) never gets called to know to release the previously held value.
For the sake of example, here's what getVariable looks like:
- (void)getVariable {
// variable is the class member
return variable;
}
Let me know if you have further questions.
Yes. self.instanceVar accesses the value through the property.
Although it is not necessarily the synthesized property. You can write your own get and set methods that can be called.

assignment of property and allocation leads to retain count of 2

I had a look at instruments and I saw that the alloc increased the retain count by 1. So far everything clear. But the assignment of the class to my property also increased the retain count to 2.
self.myProperty = [[MyClass alloc] init]
Vs.
MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable
To decrease the retain count to zero I released myCreatedVariable right after my calls. The myProperty instance variable is released in the dealloc method. Am I right that a property only is released in the dealloc method?
Now to my question:
Is the allocation and the assignment to a property always creating a retain count of 2? So don't use
self.myProperty = [[MyClass alloc] init]
because the retain count is never getting zero? Or is this only the case if I'm allocating a class?
Cheers
Your property is most probably declared as retaining or copying:
#property (retain) MyClass myProperty;
or
#property (copy) MyClass myProperty;
This calls your setter that does what its attributes say: retain! Copy will also retain.
Although it worked here, you shouldn't try to get useful information out of the retainCount property.
I cannot recommend the Memory Management Programming Guide highly enough, well worth a first, second and third read. :-)
Creating objects using the init function returns a retained instance by default. ( See the Memory Management Programming Guide)
If the property is defined with the 'retain' attribute, then your object is retained one more time.
So the right way to do is
MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable;
[myCreatedVariable release];
By the way this is good to know also when you using Arrays.
Once an object created with the alloc and init functions is added into an array, it is retained by the array, so you can release your instance after you add it in the array.
In both case, retainCount is then 1, as expected.
if your property is defined with the 'copy' attribute, you can release the object as well, and even kill it, since it has been fully copied and retained once.
( I think there is something there if you use garbage collection instead of managed memory... To check.. )
Finally if your property is set with the 'assign' attribute, only the object's adress is copied, so you should not release your original object in this case.
It is however not recommanded to use the 'assign' attribute, since you may set property with objects that you did not create yourself, and which could be released anytime, letting your property pointing in the fields...
Finally, don't forget that static creators in Cocoa do not return retained objects.
( This is a convention, exceptions may exist... )
example:
NSArray* myArray = [NSArray array];
self.myProperty = myArray;
In this case, do not release myArray, it is already done in the creator function.
Assigning it to the property will retain it.( with retain or copy attribute).
Hope it will help,
Cheers
#property (nonatomic, retain) NSString *strURL;
This will keep the Retain count = 0
When you use an accessor to initialize the strURL then the retain count increases to 1
self.strURL = [NSString stringWithString:#"http://192.168.1.25/shop.php"];
However if you had done this without using the accessor then your reference count would have remain same that is 0
strURL = [NSString stringWithString:#"http://192.168.1.25/shop.php"];
Note that when you use this variable with retain count as 0, the auto release works and the variable gets released, giving "SIGABART" error or “EXC_BAD_ACCESS” when you try to access its value.
Generally when you are using init to get your variables initialized the best practice is to use alloc.
strURL = [[NSString alloc] stringWithString:#"http://192.168.1.25/shop.php"];
Hope this helps!
Sorry ? Noooo. I'm afraid programming is trying to know things we don't know everyday !
Static creators are convenience function, to ease common objects allocations.
A lot of classes in the cocoa framework have this kind of functions. Arrays, Dictionary, Paths, ...
Let's take your class as an example, and suppose you often have to create objects of this class. You may write a function in your 'myClass' implementation like:
+(MyClass*)myClass
{
MyClass *myNewInstance = [[myNewInstance alloc] init];
return [myNewInstance autorelease];
}
Then you can rewrite your original example as:
..
self.myProperty = [MyClass myClass];
..
Straight!
Or you could write a method like
-(void)myFunction
{
MyClass* myTempObject = [MyClass myClass];
if (myTempObject) {
// do something with your temporary object
}
// Simply exit, object will be released later on.
}
It is much shorter ( we should handle the case where object creation failed ) ..
Note that this is all conventions, you can basically do has you like and create retained objects, or use a different name for the creator.
But it is safer to follow the framework rule, it then becomes a reflex when you code.
See methods like [NSDictionary dictionary], [NSArray array], [NSArray arrayWithObjects:] ,...
Cheers