Memory management when adding a UIImageView to ano

2019-05-21 07:06发布

问题:

So it looks like I have no leaks detected throughout my entire project, and I have lots of sections that do various things.

However, I found that I am having some allocation issues, proven to me with mark heap in leaks instrument, which have happened most of the time when using the iPad with an external screen. The app is programmed to behave differently when connected to an external screen.

I have a zoomable UIScrollView map section that I can go in and out of. When using the iPad by itself, and checking the mark heap, the heap growth will eventually go down to 0 bytes, which is good. However, with the external screen plugged in, an image is sent to the external screen, which uses another view controller, and checking the mark heap when exiting the map is around 6-7 MB just about every time without much decrease in the other heap growths. BAD.

The thing I found was, that I'm totally not handling the release of the external UIImageView correctly at all, and this was obvious to me when I just glanced over it. I'll explain more about that in a bit.

Important thing before I continue explaining, and I apologize for making this so long, but I swear I've heard there's an exception for not putting an alloc'd object in dealloc if it is added to another view from another view, because I don't own it, thus not responsible for dealloc'ing. Whether I dealloc it or not, I get the same behavior. But I actually don't think it would ever get to dealloc the way my code is setup currently. So I think my problem is that I'm not releasing the image view from memory... but the question remains, where do I do that in this case!

In View A's initWithFrame method, I have the view added to the external screen if it's connected:

    if(exScreenEnabled==1){
        mapImageViewEx = [[UIImageView alloc] init];

        CGPoint p = mapScrollView.contentOffset;
        mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageView.frame.size.width, mapImageView.frame.size.height);

        NSString *mapExFileLocation = [[NSBundle mainBundle] pathForResource:[map_List objectAtIndex:mapNum] ofType:@"png"];
        NSData *mapExIMGData = [NSData dataWithContentsOfFile:mapExFileLocation];
        mapImageViewEx.image = [UIImage imageWithData:mapExIMGData];

        UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];

        [containerExViewP addSubview:mapImageViewEx];

    }

In the external viewController's viewDidLoad method, a containerView had been added when the application started and the user chose the screen resolution. Working almost the same as the iPad window's view controller, it's for swapping in and out views:

CGRect frame = CGRectMake(0, 0, 1024, 768);
containerExView = [[UIView alloc] initWithFrame:frame];
[containerExView setTag:9000];

self.view = containerExView;

Let's just call this external viewController's "View B"

So this looks like where the problem starts: When the user pushes the back button when they are in the map, if an external screen is connected, View A performs an NSNotificationCenter that View B listens to, to remove subviews in View B's container. Here's the method in View B:

- (void)removeExView{
    [[self.view.subviews objectAtIndex:0] removeFromSuperview];
    NSLog(@"REMOVED EX VIEW");


    UIImage *idleExImage = [UIImage imageNamed:@"idle4.png"];
    UIImageView *idleExImageView = [[UIImageView alloc] initWithImage:(UIImage *)idleExImage];
    CGRect idleExFrame = CGRectMake(0, 0, 1024, 768);
    idleExImageView.frame = idleExFrame;
    [self.view addSubview:idleExImageView];

    [idleExImageView release];
}

The subview's are removed from View B's container at index 0, and then default image is displayed.

So, my best guess is, even though the subview was removed, which is the image view, it's not necessarily released from memory. But how would you access this? Is this even the problem? Perhaps it does have to be dealloc'd but can never get to this point because the view is unexpectedly removed first. I just don't know, because I'm not familiar yet how this situation should be handled properly. Thanks in advance for any help you can provide.

回答1:

Kind of tough to guess at this, but I'd say it's these lines

    mapImageViewEx = [[UIImageView alloc] init];
    // snipped some code for clarity
    [containerExViewP addSubview:mapImageViewEx];

    containerExView = [[UIView alloc] initWithFrame:frame];
    // snipped some code for clarity
    self.view = containerExView;

These can and should be release after they've been added to the view hierarchy

    [mapImageViewEx release];
    [containerExView release];

unless you are keeping a reference to these intentionally for something not shown in the snippets above.



回答2:

[containerExViewP addSubview:mapImageViewEx];

after this line use [containerExViewP release];