Question

I'm going through my iOS app, using "Simulate Memory Warning" as my hammer of justice, and it's causing some unexpected problems (naturally). But this is one problem that has me stumped: objects are seemingly no longer equal.

Say my view controller (we'll name it VCBob) has…

  • two separate custom UIViews as subviews (let's name those views viewA and viewB)
    • each with their own UICollectionView exposed as the property collectionView (these UICollectionViews use VCBob as their delegates)
  • a UIButton that, when pressed, pushes some other view controller (an otherwise insignificant one) on to the stack

So I tap on the UIButton and here comes the insignificant view controller. I fire off the "Simulate Memory Warning" option, and VCBob is programmed to ditch viewA and viewB inside of -didReceiveMemoryWarning, since they are being totally recreated and re-inserted into the view hierarchy on viewWillAppear (so long as they're nil at the time of viewWillAppear). Here's that implementation in VCBob:

- (void)didReceiveMemoryWarning {
    BOOL hasSuperview = self.view.superview != nil;
    [super didReceiveMemoryWarning];

    if (!hasSuperview) {
        _viewA = nil;
        _viewB = nil;
    }
}

I then tap the back button in the navigation bar, and VCBob comes back into play. The two custom UIViews are still there, and their respective UICollectionViews are loaded with content. When I tap on one of the UICollectionViewCells in either of the collection views, the -collectionView:didSelectItemAtIndexPath: method gets called on VCBob; so far, so good. That implementation looks like this.

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    if (collectionView == self.viewA.collectionView) {
        NSLog(@"Do something here!");
    } else if (collectionView == self.viewB.collectionView) {
        NSLog(@"Do something else here!");
    }
}

The problem is nothing happens — nothing gets logged. Both of those if conditions evaluate to false. Why is that? I kinda seem to think I might be doing bad things in didReceiveMemoryWarning. Should I not be disposing of views there?

Was it helpful?

Solution

If _viewA is in a view hierarchy, it is retained by its superview, so doing _viewA = nil will not release it, and it will still be there when the viewWillAppear method gets fired.

Then, in your viewWillAppear you are adding a "duplicate" of your viewA, with its own collectionView inside, placed just over the original one: you see one view, but in truth they are two views overlapped.

So, you should just add a removeFromSuperview call in your didReceiveMemoryWarning method to get rid of this

The same happens for viewB.

OTHER TIPS

Rats, I think I figured it out. I was disposing of my views in didReceiveMemoryWarning without removing them from the superview first. The UIView that I had in place was evidently still retaining instances of my stale objects, even though I had nil-ed them out.

- (void)didReceiveMemoryWarning {
    BOOL hasSuperview = self.view.superview != nil;
    [super didReceiveMemoryWarning];

    if (!hasSuperview) {
        [_viewA removeFromSuperview];
        _viewA = nil;
        [_viewB removeFromSuperview];
        _viewB = nil;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top