开发者

How come my app seems to be holding an image in memory?

开发者 https://www.devze.com 2023-01-14 09:09 出处:网络
I have an IntroViewController with a very large image, which increases the memory of my app by about 1.5MB. The image is set on a UIImageView within the View Controller\'s NIB.

I have an IntroViewController with a very large image, which increases the memory of my app by about 1.5MB. The image is set on a UIImageView within the View Controller's NIB.

Once the intro has finished, I call release on the IntroViewController, which then successfully calls dealloc on itself and calls release on the large UIImageView. However, my memory in Instruments doesn't seem to come back down again. I can test the memory difference by simply renaming the image to the UIImageView in the NIB so it can't find anything, and then the memory drops by about 1.5MB.

So why am I not getting that memory back? Is there something that I'm missing which is stopping the UIImageView from being properly dealloc'd?

Thanks,

:-Joe

------- ADDED: CODE ------

#import <UIKit/UIKit.h>

@class AppDelegate_iPhone;

@interface IntroViewController : UIViewController
{
    AppDelegate_iPhone *appDelegate;

    UIImageView *wheelImageView;
    UIView *copyOverlayView;
}

@property (nonatomic, retain) IBOutlet UIImageView *wheelImageView;
@property (nonatomic, retain) IBOutlet UIView *copyOverlayView;

- (void)startAnimation;

@end

@implementation IntroViewController

@synthesize wheelImageView, copyOverlayView;

- (void)viewDidLoad
{
    [super viewDidLoad];
    appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
    [self startAnimation];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [self.wheelImageView removeFromSuperview];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.wheelImageView.image = nil;
    appDelegate = nil;
}

- (void)dealloc
{
     [wheelImageView release];
     [copyOverlayView release];

    [super dealloc];
}

- (void)startAnimation
{
    self.wheelImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
    [UIView beginAnimations:@"wheelScale" context:nil];
    [UIView setAnimationDuration:2.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(wheelScaleDidFinish)];
    self.wheelImageView.transform = CGAffineTransformMakeScale(1.0, 1.0);
    [UIView commitAnimations];

    [UIView beginAnimations:@"copyOverlayFade" context:nil];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelay:1.0];
    self.copyOverlayView.alpha = 0;
    [UIView commitAnimations];
}

- (void)wheelScaleDidFinish
{
    [appDelegate introAnimationFinished];
}

@e开发者_JAVA技巧nd

---- EDIT

Can anyone please help? I'm stumped, and it's causing my app to crash on the iPhone due to high memory :( can't figure out how to get rid of the stupid image! Grrrr...


The UIImageView is being released, but are you sure you don't have a phantom retain on it somewhere else? If I were you I would try to track down its retains and releases. You can either do that with funky debugger tricks, tools like malloc_history, or simply by make a subclass of UIImageView:

@interface DebugImageView @end
@implementation DebugImageView
  - (id) retain {
    NSLog(@"retained");
    return [super retain];
  }

  - (void) release {
    NSLog(@"release");
    [super release];
  }

  - (void) dealloc {
    NSLog(@"dealloc");
    [super dealloc];
  }

Just change the class of the UIImageView object in IB to DebugImageView, and you should be good to go. You can also put break points on those to see where they are called, or just make calls to backtrace() where I have logging statements.

If the object is in fact being deleted, then your memory increase is probably not serious, and is most likely due to either a large reusable buffer object that is lazily evicted, or heap fragmentation. 1.5MB does seem a bit high for that sort of thing though, so I suspect it is a an over retain.


Okay so I found the solution, but am very surprised by it!

Not only did I have to take the UIImageView out of IB and create it dynamically, I had to avoid the use of the convenience method for loading the image. Instead of:

wheelImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"wheel-intro.png"];
[self.view addSubview:self.wheelImageView];
[wheelImageView release];

I had to use:

NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"wheel-intro" ofType:@"png"];
wheelImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
wheelImageView = [[UIImageView alloc] initWithImage:wheelImage];
[wheelImage release];
[self.view addSubview:self.wheelImageView];
[wheelImageView release];

Now when I do [wheelImageView removeFromSuperview] in the viewDidDisappear handler, everything gets cleaned up correctly.

What I find REALLY bizarre, is that putting the image in Interface Builder is identical in memory management to using a convenience method in XCode. And neither work properly! Note to self: Stop using convenience methods...

0

精彩评论

暂无评论...
验证码 换一张
取 消