i'm testing my app on Instruments,
and I see that my UIImage and UIImageView are memory-leaking like crazy...
I'm basically using recursion, so same variables get to load different images on each call.
nextImageName = [[NSString alloc] init];
nextImageName2 = [[NSString alloc] init];
nextImageName = [[currentPlayers objectAtIndex:playerIndex] retain];
nextImageName2 = [[currentPlayers objectAtIndex:(playerIndex+1)] retain];
nextImage = [[UIImage alloc] init];
nextImage2 = [[UIImage alloc] init];
nextImage = [UIImage imageNamed:nextImageName];
nextImage2 = [UIImage imageNamed:nextImageName2];
nextImageView = [[UIImageView alloc] init];
nextImageView2 = [[UIImageView alloc] init];
nextImageView = [[UIImageView alloc] initWithImage:nextImage];
nextImageView2 = [[UIImageView alloc] initWithImage:nextImage2];
NSLog(#"r:%d",currentRound);
NSLog(#"%d vs. %d", playerIndex, playerIndex+1);
buttonOne = [[UIButton alloc] init];
buttonTwo = [[UIButton alloc] init];
playerOne = nextImageView;
playerTwo = nextImageView2;
playerOne.frame = CGRectMake(180.0, 200.0, 275.0, 275.0);
playerTwo.frame = CGRectMake(550.0, 200, 275.0, 275.0);
buttonOne.frame = CGRectMake(180.0, 200.0, 275.0, 275.0);
buttonTwo.frame = CGRectMake(550.0, 200.0, 275.0, 275.0);
[buttonOne addTarget:self action:#selector(announceWinner:)
forControlEvents:UIControlEventTouchUpInside];
[buttonTwo addTarget:self action:#selector(announceWinner2:)
forControlEvents:UIControlEventTouchUpInside];
Could anyone please help me? This is driving me nuts..
I originally had release for all the variables at dealloc, but it seemed it didn't go into dealloc, so I also put it in viewDidUnload and didReceiveMemoryWarning.
I think the problem is this:
"I'm basically using recursion, so same variables get to load different images on each call"
...coupled with this:
"I originally had release for all the variables at dealloc, but it seemed it didn't go into dealloc, so I also put it in viewDidUnload and didReceiveMemoryWarning"
So essentially, if I understand your code correctly, you were making several passes through the alloc/init section over the lifetime of your class, but only ever calling release once, when the class itself is deallocated. I would expect that to leak like crazy.
You should be able to fix it by changing the alloc/init section to follow a pattern like:
if (nextImageName) {
//if it was previously set, release it so that the old instance doesn't leak
[nextImageName release];
}
nextImageName = [[NSString alloc] init];
if (nextImageName2) {
[nextImageName2 release];
}
nextImageName2 = [[NSString alloc] init];
//and so on...
This assumes that these variables are all declared as instance-variables on your class, and that in init you set them all to nil, like so:
- (void) init {
if ((self = [super init])) {
//set default values
nextImageName = nil;
nextImageName2 = nil;
//and so on...
//do other setup things here
}
}
nextImageName = [[NSString alloc] init];
nextImageName = [[currentPlayers objectAtIndex:playerIndex] retain];
there you have your first memleak.. you are allocating a string and then you replace that object with the one one from the array.
you can simply remove the first line.. you don't have to allocate a object before getting one out of an array.
But without seeing more code we can't see what you are releasing later.. I hope you are releasing stuff later ;)
You are allocating and init'ing each object and then increasing the retain count again.
Anytime you call alloc, copy, new or retain...the retain count of the object goes up by 1. When you release, the retain count goes down by 1. So when you type
nextImageName = [NSString alloc] init];
and then
nextImageName = [[currentPlayers objectAtIndex:playerIndex] retain];
nextImageName now has a retain count of 2. If you only used the second line, you would be fine. You don't need to allocate a new object, you just need to retain the one that's being returned to you.
Likewise nextImageView and nextImageView2 are being allocated twice and therefore have a retain count of 2. You only need the second call you're making.
nextImageView = [UIImageView alloc] initWithImage:nextImage];
Hope this helps.
Try this code. It will clear the memory leaks on UIImage and UIImageView.
nextImageName = [NSString string];
nextImageName2 = [NSString string];
nextImageName = [[currentPlayers objectAtIndex:playerIndex] retain];
nextImageName2 = [[currentPlayers objectAtIndex:(playerIndex+1)] retain];
nextImage = [UIImage imageNamed:nextImageName];
nextImage2 = [UIImage imageNamed:nextImageName2];
nextImageView = [[UIImageView alloc] initWithImage:nextImage];
nextImageView2 = [[UIImageView alloc] initWithImage:nextImage2];
NSLog(#"r:%d",currentRound);
NSLog(#"%d vs. %d", playerIndex, playerIndex+1);
Related
In my app, I use UIImageView and UIScrollView to show a lot of images (every time there are about 20 images and every image is about 600px*500px and size is about 600kb).
I use this code to accomplish this function:
// Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
imageData = nil;
iv = nil;
iv.image = nil;
filePath = nil;
[imageData release];
[filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
But every time I initialize this function, the memory will increase about 5MB. Actually I release UIImageView, UIimage and UIScrollView (vi.image=nil, [vi release]) but it doesn't work, the allocated memory is not getting released. BTW, I used my friend's code first vi.image = nil then vi = nil; but the pictures are not getting displayed on scrollview.
The main problem, as I see it, is that you're setting your local variables to nil and then you proceed to try to use those local variables in methods like release and the like, but because they've been set to nil, those methods now do nothing, and the objects with the +1 retainCount (or now +2 because you've added them to your view) are never released.
Thus, I'd suggest the following:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
// Don't set these to nil, or else subsequent release statements do nothing!
// These statements are actually not necessary because they refer to local
// variables so you don't need to worry about dangling pointers. Make sure
// you're not confusing the purpose of setting a pointer to nil in ARC to
// what you're doing in your non-ARC code.
//
// imageData = nil;
// iv = nil;
// You don't want to set this to nil because if iv is not nil, your image
// will be removed from your imageview. So, not only is this not needed,
// but it's undesired.
//
// iv.image = nil;
// This statement is not necessary for the same reason you don't do it
// to imageData or iv, either. This is probably even worse, though, because
// filePath is not a variable that you initialized via alloc. You should
// only be releasing things you created with alloc (or new, copy, mutableCopy,
// for which you issued a retain statement).
//
// filePath = nil;
[imageData release];
// filePath is a +0 retainCount already, so don't release. You only release
// those items for which you increased retainCount (e.g. via new, copy,
// mutableCopy, or alloc or anything you manually retained).
//
// [filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Thus, your code would be simplified (and corrected) to probably just be:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
[imageData release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Or you could further simplify your code through the use of autorelease:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)] autorelease];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
By the way, the statement (with autorelease):
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
could probably be simplified to:
UIImage *imageData = [UIImage imageWithContentsOfFile:filePath];
This gives you a UIImage, with a +0 retainCount (i.e. you don't have to release it) from your file.
So, a few final observations:
You really should probably review and study the Advanced Memory Management Programming Guide. It's dense reading if you're new to memory management, but mastery of these concepts (especially in non-ARC code) is critical.
If you haven't, I'd encourage you to run your code through the static analyzer ("Product" - "Analyze" or shift+command+B). I'd be surprised if many (if not most) of these issues wouldn't have been identified for you by the analyzer. You should have zero warnings when you run your code through the analyzer.
If you want to take this to the next level, you might want to be far more conservative about your memory management. The governing principle would be a system design that only loads the images that are needed at the UI at any given time, which involves not only calvinBhai's excellent suggestion of lazy loading of images (i.e. don't load images into memory until your UI really needs them), but also a pro-active releasing images once they've scrolled off the screen. Maybe you don't need to worry about it in your app, because you're only dealing with 20 images at a time, but if any of your portfolios/galleries expanded to 100 or 1000 images, the idea of keeping all of those in memory at any given time is just a bad idea. This is a more advanced concept, so maybe you should focus on the basic memory management problems of your existing code first, but longer term, you might want to contemplate lazy loading and pro-active releasing of images.
If memory is your concern,
try lazy loading the images = Load the visible image, the next and previous image. You dont have to have all images added to your klpscrollview.
Once you figure out lazy loading the images onto your scrollview, then you can think of fixing the images not showing on your scrollview.
Easier would be to search for "lazy load uiimage uiscrollview"
In my app, I load UIViewController into an array from a .plist, and then, I need to get those VC's out. The problem is, since the number of VC's is not always the same, then I don't know how many I'm getting out each time. So I'm looking for a better engeneered solution - better iteration, rather than hard coding.
For example:
NSMutableArray *views = [[NSMutableArray alloc] init];
for (int i = [currentList count]; i > 0; i--) {
UIViewController *view = [[UIViewController alloc] init];
view.title = [NSString stringWithFormat:#"dgdg - %i", i];
[views addObject:view];
}
So there is my array of VC's, and now:
myIvar = [[CustomSubClass alloc] initWithViewControllers:**help** nil];
I tried:
myIvar = [[CustomSubClass alloc] initWithViewControllers:[views copy], nil];
and:
myIvar = [[CustomSubClass alloc] initWithViewControllers:[NSIndexSet..., nil];
I tried:
myIvar = [[CustomSubClass alloc] initWithViewControllers:[views objectAtIndex:0]... nil];
but none of it worked. Thanks in advance.
The syntax you want is like this:
[[CustomSubClass alloc] initWithViewControllers:[views objectAtIndex:0], [views objectAtIndex:1], [views objectAtIndex:2], nil];
Basically just repeat have all your arguments separated by commas, then always have the final argument be nil.
views is an array and you can pass this directly as a parameter like so:
myIvar = [[CustomSubClass alloc] initWithViewControllers:views];
Until yesterday I thought that I had understood the iPhones memory management.
Well here is my problem:
// .h file
#property(nonatomic, retain) NSMutableDictionary *dicParams;
#property(nonatomic, retain) NSMutableDictionary *dicReferences;
#property(nonatomic, retain) FtMonitorHandler *monitorHandler;
// .m file
#synthesize dicParams, dicReferences, monitorHandler;
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
- (void)dealloc {
[monitorHandler release];
[dicParams release];
[dicReferences release];
[super dealloc];
}
If I set somewhere else, after the viewcontroller's allocation for example
self.dicParams = dicValues;
… it will turn into a leak
My understanding of setting instance variables with "self. …" was, that the current value will be "released" and then set with "retain".
I tried a little bit with instruments. Results:
-(void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = [[NSMutableDictionary alloc] init];
}
-(void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = nil;
self.dicParams = [[NSMutableDictionary alloc] init];
}
- (void)createWithoutLeak {
if(dicParams != nil) [dicParams release];
self.dicParams = [[NSMutableDictionary alloc] init];
}
Have I missed something, or is this the behavior as it should be?
EDIT: I tried to implement the suggested changes. It works fine, as long, as my variable is not GUI element. (UIView, UILabel, etc)
The autorelease will cause an app crash after a memory warning
- (void)loadView {
[super loadView];
// ... here is some other stuff ...
self.lblDeparture = [[[UILabel alloc] init] autorelease];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
self.lblDeparture = nil;
}
- (void)dealloc {
[lblDeparture release];
[super dealloc];
}
I'm not quite sure, but I assume that the following lines are the real issue:
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, INFO_VIEW_HEIGHT);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView addSubview:lblDeparture];
[lblDeparture release]; // is this correct?
[self.view addSubview:imageView];
[imageView release];
if you init you need to auto release.
-(void)dontCreateAnotherLeak {
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
self.dicParams = nil;
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
}
the easier equivalent is to use the convenience accessor.
self.dicParams = [NSMutableDictionary dictionary];
if you would like to handle this yourself. On top of the #synthesize dictParams; you will also want to create your own setter.
-(void)setDictParams:(NSMutableDictionary*) newDictParams
{
if (dictParams != newDictParams)
{
[dictParams release];
dictParams = [newDictParams retain];
}
}
this is a little simple. but essentially what the compiler creates with the retain modifier added to the #property tag
If you set a instance variable for which you have specified retain in property retain count becomes 1
Now as you call with reference to self as in case “self.variable = value” increase the retain count by 1, So the total retain count becomes 2.
So now to release it you need to bring retain count to 0. Hence you need to release it twice.
Hopew this helps.
I am not sure I understand the question fully, however your second part is easily explained...
-(void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = [[NSMutableDictionary alloc] init];
that's clear...
now but this one
-(void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = nil;
self.dicParams = [[NSMutableDictionary alloc] init]; }
does not release the first alloced self.dicParams but rather forgets any reference to it by setting it to nil and then resetting it with a new one. Setting to nil is not equal to release. If you would have created the first one with autorelease and then set it to nil it's something different. That should work correctly. And that's exatcly what you do with your 3rd example!
Now as to your inital question, what is it that leaks when you write
self.dicParams = dicValues;
?
the variable self.dicParams should just hold the value until you release it again
I recommend you read Apple's Memory Management Programming Guide carefully. http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
It's all explained in there.
There are a couple of obvious mistakes I can see that you are making.
Firstly, you shouldn't use accessors in init or dealloc.
So, this
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
should be
- (id)init {
self = [super init];
if (self) {
dicParams = [[NSMutableDictionary alloc] init];
dicReferences = [[NSMutableDictionary alloc] init];
monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
Secondly, when you set a retained property, the you need to release the whatever you are setting it to.
So, this
self.dicParams = [[NSMutableDictionary alloc] init];
should be
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
or you can do this
NSMutableDictionary *newDicParams = [[NSMutableDictionary alloc] init];
self.dicParams = newDicParams;
[newDictParams release];
The setter generated by #synthesize for a (readwrite, retain, nonatomic) property looks something like this:
- (void) setSomething: (id) newSomething;
{
if (something != newSomething) {
[something release];
something = [newSomething retain];
}
}
The old object pointed to by the instance variable something will be released while the new object will be retained.
Your mistake is the object creation. You create your dictionary with [[NSDictionary alloc] init]. This dictionary has a retain count of 1. Your setter retains the object, so the new retain count is 2. When you call the setter again the retain count of your original dictionary correctly gets decreased - it’s 1 again. For the dictionary to be freed you’d have to release it again. For this there is autorelease. An autoreleased object will get released some time later. So the correct code to set your property would be
self.something = [[[NSDictionary alloc] init] autorelease];
or even better using the convenience allocator
self.something = [NSDictionary dictionary];
You really should read and understand Apple’s memory management guide - it’s all explained in there.
By the way, I talked about retain counts here. It’s OK to think about them, but you should never ask an object about it’s retain count, that value is useless, since it’s rarely what you would think.
I'm having issues with a singleton I've created. It contains two NSMutableDictionary's, which are read and used in three views (and some modal views) throughout the app.
I've added an MKMapView t plot some of the venues inside the dictionaries on a map. When I use the exact same method/function used in every other view to access the data, I receive an EXC_BAD_ACCESS error pertaining to a deallocated dictionary. This comes from NSZombieEnabled:
CFDictionary retain: message sent to deallocated instance
In a dsym'ed trace, it is the replacement of one dictionary with another that is causing grief. The code I'm using to call the function comes from a MKAnnotationView click:
UIControl *tempButton = sender;
NSString *selectedEventsString = [self.eventsArray objectAtIndex:tempButton.tag];
NSLog(#"eventString: %#", selectedEventsString);
[[EventsManager eventsManager] changeSelectedEventsDictionaryTo:selectedEventsString];
[tempButton release];
[selectedEventsString release];
"selectedEventsString" is coming out to a perfectly corresponding event.
The corresponding code in EventsManager:
-(void)changeSelectedEventsDictionaryTo:(NSString *)eventName {
NSLog(#"singleton: %#", eventName);
self.eventString = eventName;
self.selectedEventsDictionary = [self.eventsDictionary objectForKey:eventName];
}
Both selectedEventsDictionary and eventsDictionary are set as #property (nonatomic, retain) in the .H file, and this is the init function:
+ (EventsManager*)eventsManager {
if (eventsManager == nil) {
eventsManager = [[super allocWithZone:NULL] init];
eventsManager.eventsDictionary = [[NSMutableDictionary alloc] init];
eventsManager.selectedEventsDictionary = [[NSMutableDictionary alloc] init];
eventsManager.eventString = [[NSString alloc] init];
eventsManager.mode = [[NSString alloc] init];
}
return eventsManager;
}
This is an example of code used in other views that works fine:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
NSString *eventString = [self.eventsArray objectAtIndex:row];
[[EventsManager eventsManager] changeSelectedEventsDictionaryTo:eventString];
//Modal display code here
}
Any help would be greatly appreciated! I think I've provided all relevant code but let me know if more is needed.
Cheers!
Where to start! I will point out some things that I do see wrong.
First Example. Do not release tempButton and selectedEventString as you never explicitly called retain/copy or alloc and init on them.
UIControl *tempButton = sender;
NSString *selectedEventsString = [self.eventsArray objectAtIndex:tempButton.tag];
NSLog(#"eventString: %#", selectedEventsString);
[[EventsManager eventsManager] changeSelectedEventsDictionaryTo:selectedEventsString];
//DO NOT RELEASE THESE YOU NEVER RETAINED THEM!
[tempButton release];
[selectedEventsString release];
Your static eventsManager is not thread safe which may not be a issue for you but should definitely be looked into.
Read the comments for the following code example
+ (EventsManager*)eventsManager {
if (eventsManager == nil) { //<-- Not thread safe
//DO NOT CALL SUPER USE self
//eventsManager = [[self alloc] init];
eventsManager = [[super allocWithZone:NULL] init];
//You need to autorelease these values or use an autoreleased static method
//eventsManager.eventsDictionary = [NSMutableDictionary dictionary];
//eventsManager.selectedEventsDictionary = [NSMutableDictionary dictionary];
eventsManager.eventsDictionary = [[NSMutableDictionary alloc] init];
eventsManager.selectedEventsDictionary = [[NSMutableDictionary alloc] init];
//Do not bother setting these at all or just set them to nil
eventsManager.eventString = [[NSString alloc] init];
eventsManager.mode = [[NSString alloc] init];
}
return eventsManager;
}
Make sure all of those properties are set to retain or copy and that may fix your problem. If you still have an issue after these fixes you can update your question and I will update my answer.
I am new to iPhone development. I have a memory leak issue in the following code. If anyone knows why it's happening please help me.
for(int i=0;i<size;i++)
{
NSString *CellIdentifier1;
if(universalApp==2)
{
CellIdentifier1 = #"CustomThumbImageTableCell_iphone";
cell = [[[CustomThumbImageTableCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier1] autorelease];
//NSLog(#">>>>> Creating image >>>>>>>>");
cell.thumbImageView = [[CustomImageView alloc] initWithFrame:CGRectMake(4, 4, 83, 101)];
[imgViewArray addObject:cell.thumbImageView];
[cell.thumbImageView release];
}
Moreover, use auto release pool,
for(int i=0;i<size;i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
...
cell.thumbImageView = [[[CustomImageView alloc] initWithFrame:CGRectMake(4, 4, 83, 101)] autorelease];
...
[pool release];
}
And check imgViewArray, as you know, the retain count of an object added to an NSMutableArray is increased by 1.