I then released the tableList in viewDidUnload. But, when I run the app with Leaks it has an issue with the first line of code: tableList = [[NSMutableArray alloc] init];. I am at a loss.
I then released the tableList in viewDidUnload. But, when I run the app with Leaks it has an issue with the first line of code: tableList = [[NSMutableArray alloc] init];. I am at a loss.
Don't use instance variables directly. See the properties link in my signature for more info.
Don't use instance variables directly. See the properties link in my signature for more info.
The autorelease is fine. The retain is a problem.
Brian,
Thank you for writing. I did read your tutorial before I wrote this question. (Also the documentation from Apple. There is a lot of new vocabulary for me...but I am trying to get what I'm doing.) I understand that the first part of my question pertains directly to figures 8 and 9 of your tutorial, and that I'm making a mistake in using the instance variable directly. Where you lose me is where rather than Myclass *myInstanceVariable =... It's Myclass *newItem=... I am confused about what my newItem would be.
But, I know that if I do this: NSMutableArray *tableList = [[NSMutableArray alloc] init]; I get a ton of warnings that I am hiding myInstanceVariable.
You didn't retain the cell, you retained the string you were putting in to the text label.
As far as the cell itself, you should release anything created with alloc, new, copy, or retain. The dequeueReusableCell line does not involve any of those, so that line of code does not produce an object that you should release.
So the complication arises if there is no cell available for reuse. The return from that call in that case is nil. The whole "if (cell == nil)" part is for the case of "there was no cell available to reuse, therefore you must build a new one".
Let's simplify the code a bit to see what's going on:
Case A - There is a cell available
Line 1: gets populate with an object you don't need to release
Line 2: is false
Line 3-5: never happen
Line 6: return an object you didn't need to release, so no problem.
Case B - No cell is available.
Line 1: is nil
Line 2: is true
Line 4: creates an object that you DO need to release
Line 6: return an object you were supposed to release, but didn't. That's a leak.
The issue here is that there are 2 possible creation points - 1 where a manual release is required, one where it isn't - but only one return point. So you have 2 possible solutions: 1) The return needs to somehow know the difference, or 2) make a change so that both creation points have the same behavior. If #1 is possible, I don't know how to do it, so let's focus on #2.
Case C - Make a return release necessary
This would be done by changing the dequeue line: add a retain.
This object now must be manually released in either case, and this would be done by changing the return line:
Code:
return [cell autorelease];
However, even though in this case the only way a new cell will be created is if the cell variable is nil, in general it is a bad idea to have an variable that could change later contain an object that needs to be released. That's just begging for a leak. This is probably why pretty much every example does:
Case D - Make a return release unnecessary
This would be done by changing the cell creation line #4:
Code:
cell = [[[... alloc] init] autorelease];
Now regardless of new-vs.-reused, no further release of the cell is necessary.
But, I know that if I do this: NSMutableArray *tableList = [[NSMutableArray alloc] init]; I get a ton of warnings that I am hiding myInstanceVariable.
With the NSMutableArray * part at the beginning, you are declaring a new variable - a LOCAL variable. However, in this case, your local variable has the same name as your instance variable. Don't do that.
With the NSMutableArray * part at the beginning, you are declaring a new variable - a LOCAL variable. However, in this case, your local variable has the same name as your instance variable. Don't do that.
Now I've crashed entirely- App loads and then crashes.
Here's what I tried-
In header- created the instance variable- NSMutableArray *tableList;
@property (nonatomic,retain) NSMutableArray *tableList;
In implementation:
@synthesize tableList=tableList; (you did say it was OK for the property and the variable to have the same name)
In viewDidLoad:
NSMutableArray *HomeList= [[NSMutableArray Alloc] init]]
[self settableList: HomeList]; (***I received a warning that the viewcontroller might not respond to settableList***)
[HomeList addobject:@"Object1"];
[HomeList addobject:@"Object2"];
[self setTitle:@"Home"];
When I tried build and go- the app opened the loading screen and then crashed. When I undid every change that I had made, then tried build and go- the same thing- loading screen, then crash.
I am confused and I have more questions-
I have used the instance variable "tableList" in every header and implementation file in a drill-down app. Is that a problem?
If I do not use the instance variable directly in the implementation file, then do I need to replace every use of the instance variable?
Now I've crashed entirely- App loads and then crashes.
Here's what I tried-
In header- created the instance variable- NSMutableArray *tableList;
@property (nonatomic,retain) NSMutableArray *tableList;
In implementation:
@synthesize tableList=tableList; (you did say it was OK for the property and the variable to have the same name)
That is fine, although if you do that, there isn't much of a reason to do name=name. Just do @synthesize name;
Quote:
Originally Posted by MMS
In viewDidLoad:
NSMutableArray *HomeList= [[NSMutableArray Alloc] init]]
[self settableList: HomeList]; (***I received a warning that the viewcontroller might not respond to settableList***)
[HomeList addobject:@"Object1"];
[HomeList addobject:@"Object2"];
[self setTitle:@"Home"];
setTableList:
By convention, variables should begin with a lowercase letter, so homeList.
You didn't show it here, so I'll add that you need to release homeList here before you leave viewDidLoad.
Quote:
Originally Posted by MMS
When I tried build and go- the app opened the loading screen and then crashed. When I undid every change that I had made, then tried build and go- the same thing- loading screen, then crash.
It crashed because settableList doesn't exist, so it failed on the attempt. Don't ignore warnings; fix them.
Quote:
Originally Posted by MMS
I am confused and I have more questions-
I have used the instance variable "tableList" in every header and implementation file in a drill-down app. Is that a problem?
Not at all. Just keep in mind that each one is unique to each class, so you have to keep passing that array to each controller in order for each one to operate on the same data.
Quote:
Originally Posted by MMS
If I do not use the instance variable directly in the implementation file, then do I need to replace every use of the instance variable?
That is fine, although if you do that, there isn't much of a reason to do name=name. Just do @synthesize name;
setTableList:
By convention, variables should begin with a lowercase letter, so homeList.
You didn't show it here, so I'll add that you need to release homeList here before you leave viewDidLoad.
It crashed because settableList doesn't exist, so it failed on the attempt. Don't ignore warnings; fix them.
Not at all. Just keep in mind that each one is unique to each class, so you have to keep passing that array to each controller in order for each one to operate on the same data.
I don't understand the question.
What I meant by the last question is that myInstanceVariable- tableList appears many times in my implementation file, not just in the viewDidLoad- e.g.
number of rows in table-
return [tableList count];
Or pushing view controllers-
if ([[tableList objectAtIndex:indexPath.row] isEqual:@"Ferrovia Railway Station"]) ...
Should I be replacing those uses of my instance variable with my local variable?
Oh, I see. Well, there's probably a difference between what you can do, and what I do.
Any time you are simply reading the value, you can use the instance variable directly. If you are attempting to switch objects, then you should not use the instance variable directly.
I never use instance variables directly, with the exceptions as noted in my properties thread. So those same examples in any of my programs would look like:
Code:
return [[self tableList] count];
if ([[[self tableList] objectAtIndex:....)
Whether or not you even have a local variable is up to you. If you wanted to, you could certainly do this:
Code:
NSMutableArray *theList = [self tableList];
If you do that, might as well use it, so then the code becomes:
Code:
return [theList count];
if ([[theList objectAtIndex....)
Oh, I see. Well, there's probably a difference between what you can do, and what I do.
Any time you are simply reading the value, you can use the instance variable directly. If you are attempting to switch objects, then you should not use the instance variable directly.
I never use instance variables directly, with the exceptions as noted in my properties thread. So those same examples in any of my programs would look like:
Code:
return [[self tableList] count];
if ([[[self tableList] objectAtIndex:....)
Whether or not you even have a local variable is up to you. If you wanted to, you could certainly do this:
Code:
NSMutableArray *theList = [self tableList];
If you do that, might as well use it, so then the code becomes:
Code:
return [theList count];
if ([[theList objectAtIndex....)
In the above example is *theList supposed to be a local variable? The same one that was used in viewDidload?
And, if, in the viewDidLoad I use a local variable, and I add the objects to the local variable, then don't I need to use the local variable in if ([[someVariable objectAtIndex...)?
Also, I assume since I retained the property tableList in the the header file, that I need to release it in the implementation file? Where should I release it?
Can you recommend a good source for me to read more? I'd like to actually understand why I have an instance variable when everything that I'm getting and setting seams to depend on the local variable.
When I've added scrollViews they've had an instance variable and a property, and been released in the dealloc method. Leaks isn't telling me that I have memory problems there...??