Ok so here's what I'm doing.
NSMutableArray *array = [[NSMutableArray alloc] init];
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
UIView *tempview2 = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView2];
[array release];
Will the releasing of the array, release the two allocated UIViews as well?
If you copy, alloc, retain, or new something, you are responsible for sending it either release or autorelease.
You said [[UIView alloc] init...] so you must release the resulting object.
You are responsible for releasing the views since you created them. Here is how it goes:
You create the views with a retain count of 1.
When they are added to the array, it will retain them (retain count = 2).
When you release the array, it will release the views (retain count = 1).
You still need to release them.
The correct code would be:
NSMutableArray *array = [[NSMutableArray alloc] init];
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
[tempview release];
UIView *tempview2 = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView2];
[tempview2 release];
[array release];
Related
I wish to create multiple instances of UIView so i figured instead of creating new variables i'd allocate one UIView and then reallocate it again to create another UIView. Is this ok? Plus am I releasing the view properly or is the retain count of tempview is 2 after 2 allocations and a release just brings the retain count to 1?
NSMutableArray *array = [[NSMutableArray alloc] init];
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
[tempview release];
[array release];
You need to release tempView before you re-assign it or else it will leak.
NSMutableArray *array = [[NSMutableArray alloc] init];
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
[tempView release]; //you need this to avoid leaking at the next line
tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
[tempview release];
[array release];
Alternately, you could autorelease tempView each time you alloc/init it, but it's better to release when you can and only use autorelease when you have to.
also, if all views you create have the same frame you might do the same in a loop:
const int kViewCount = 8;
NSMutableArray * array = [[NSMutableArray alloc] initWithCapacity:kViewCount];
for(int i = 0; i < kViewCount; ++i)
{
UIView *tempview = [[UIView alloc] initWithFrame:CGRectMake(15, 30, 320, 460)];
[array addObject:tempView];
[tempView release];
}
just set kViewCount to the number of views you need to create
inside the UIViewController, the tempview2 is not showing up at all. only tempview is showing up.
-(id) init:(NSData*) imageData
{
if ((self = [super init])) {
tempimage= [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pic1" ofType:#"png"]] autorelease];
tempview=[[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
[tempview setImage:tempimage];
[self.view addsubview tempview];
}
return self;
}
-(void) viewdidload{
tempimage2= [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pic2" ofType:#"png"]] autorelease];
tempview2=[[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
[tempview2 setImage:tempimage2];
[self.view addsubview tempview2];
}
if I do this then everything is OK,
-(id) init:(NSData*) imageData
{
if ((self = [super init])) {
tempimage= [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pic1" ofType:#"png"]] autorelease];
tempview=[[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
[tempview setImage:tempimage];
[self.view addsubview tempview];
tempimage2= [[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pic2" ofType:#"png"]] autorelease];
tempview2=[[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
[tempview2 setImage:tempimage2];
[self.view addsubview tempview2];
}
return self;
}
This is not a direct answer to your question but a good practice of viewcontroller initialization and view loading in general:
In the init method you should only initialize ivars or other class data which does not pertain to the view. Doing otherwise breaks the notion of lazy loading. During the init method of you view controller the view does not exist yet.
In the viewDidLoad method you should perform your view setup. At this stage the view is actually loaded and it is the time to set it up properly.
I would encourage you to therefore move your view setup calls into the viewDidLoad and see if the problem persists or not.
Good luck.
I agree with MiKL.
But anyway getting back to your question did you forget to call [super viewDidLoad]? Maybe that's the issue here?
Also, as a best practice, release views after adding them as subviews to something else (adding a view as a subview to another view increases it's retain count).
Can someone point me in the right direction. When I load this file in as a nib, and unload it, and reload it instruments says I'm getting a memory leak. Specifically, it's says that where I set the compareOptions NSMutableArray, and where I call [vc release].
CompareOptions is a synthesize property that is also released in the dealloc.
Many thanks in advance.
- (void)viewDidLoad{
[super viewDidLoad];
//NSLog(#"Comparison.viewDidLoad");
self.compareOptions = [[NSMutableArray alloc] init];
self.tabs = [[ComparisonTabs alloc] initWithFrame:CGRectMake(450, 85, 650, 50)];
//NSDictionary * currComparison = (NSDictionary*)[data objectAtIndex:0];
//NSArray * correctOptions = [currComparison objectForKey:#"correct"];
for(int i = 0; i < 3; i++)
{
UIViewController * vc = [[UIViewController alloc] initWithNibName:#"ComparisonOptions" bundle:nil];
ComparisonOptions * options = (ComparisonOptions *)vc.view;
[options setup];
options.index = i;
//options.frame = CGRectMake(355 + (306 * i), 475, options.frame.size.width, options.frame.size.height);
//[options setCorrect:[correctOptions objectAtIndex:i]];
[vc release];
[self.view addSubview:options];
[self.compareOptions addObject:options];
}
[self.view addSubview:self.tabs];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tabSelectedHandler:) name:#"tabSelected" object:nil ];
[self update:0];}
how does the property of compareOptions and tabs look like? Does it retain your objects?
If it does retain, then you'll get a double retain if you use the setter and alloc.
self.compareOptions = [[NSMutableArray alloc] init];
^ retains ^^^^^ retains
self.tabs = [[ComparisonTabs alloc] initWithFrame:CGRectMake(450, 85, 650, 50)];
^ retains ^^^^^ retains
you could use this instead
self.compareOptions = [NSMutableArray array];
self.tabs = [[[ComparisonTabs alloc] initWithFrame:CGRectMake(450, 85, 650, 50)] autorelease];
UIViewController * vc = [[UIViewController alloc] initWithNibName:#"ComparisonOptions" bundle:nil];
ComparisonOptions * options = (ComparisonOptions *)vc.view;
[vc release];
[self.view addSubview:options];
vc.view (ie options) will be deallocated at the same time vc will be deallocated. And this happens when you call [vc release]. You can't use options after this.
You should release vc after you've added the view to the subview.
And you should think about better class names. I would never assume that ComparisonOptions is a View. It sounds more like NSCaseInsensitiveSearch etc. You know, like it would be an option.
I'm trying to add objects to this NSArray (labelArray) but for some reason, it returns as (null) in NSLog every time, and the count remains at 0.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(howFarAlong, howFarDown, 50, 70)];
label.text = #"text";
[self.view addSubview:label];
[labelArray addObject:label];
NSLog(#"%#", labelArray);
[label release];
An NSArray is immutable. If you want to call -addObject:, use NSMutableArray. If labelArray is an NSArray, then that should crash. If it doesn’t crash, then it’s probably nil, and you haven’t initialized it. Some code that will work:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(howFarAlong, howFarDown, 50, 70)];
label.text = #"text";
[self.view addSubview:label];
if (labelArray == nil) {
labelArray = [[NSMutableArray alloc] init];
}
[labelArray addObject:label];
NSLog(#"%#", labelArray);
[label release];
You need to use an NSMutableArray if you want to change the data in your array. NSArray can only be used to create static arrays.
You probably also receive a message from the compiler stating that NSArray may not respond to 'addObjext'. This is your clue that the object you are using won't perform the requested selector (method). In this case, you are trying to change an immutable object, which won't work. You need to use an NSMutableArray. I suggest you read up on the differences in Apple's documentation.
I tested the code below. The count is 1 after the lable is added.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(howFarAlong, howFarDown, 50, 70)];
label.text = #"text";
[self.view addSubview:label];
NSArray *labelArray = [NSArray arrayWithObject:label];
NSLog(#"Count: %d", labelArray.count);
According to the docs, you do one release per alloc or retain (etc)
However what about when using retain propertys?
eg:
HEADER
#property(retain)UIView *someView;
IMPLEMENTATION
/*in some method*/
UIView *tempView = [[UIView alloc] init]; //<<<<<ALLOC - retain count = +1
[tempView setBackgroundColor:[UIColor redColor]];
self.someView = tempView; ///<<<<<RETAIN - retain count = +2
[tempView release]; ///should I do this?
or a different version of the IMPLEMENTATION
self.someView = [[UIView alloc] init]; //<<<<<ALLOC & RETAIN - retain count = +2
//now what??? [self.someView release]; ????
EDIT: I didn't make it clear, but I meant what to do in both circumstances, not just the first.
/*in some method*/
UIView *tempView = [[UIView alloc] init]; //<<<<<ALLOC - retain count = +1
[tempView setBackgroundColor:[UIColor redColor]];
self.someView = tempView; ///<<<<<RETAIN - retain count = +2
[tempView release]; ///should I do this? // YES!!!!
And you should also release all retain properties in your dealloc method, before [super dealloc].
Your first version is correct. There's only one ongoing reference to the view, so a retain count of 1 is appropriate.
For the second sample, you can use autorelease:
self.someView = [[[UIView alloc] init] autorelease];