Reputation: 488
I don't understand the different behavior I am observing with my iOS application when I am programmatically removing subviews using Objective-C and the UIView willRemoveSubview method.
Method 1
In my ViewController class I add a UIVisualEffectView as a subview for the ViewController's view:
- (void)blurView {
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurEffectView.frame = self.view.bounds;
blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view insertSubview:blurEffectView atIndex:5];
}
This method is called in response to some action by the user.
The blurEffectView itself is a private variable of my ViewController class defined in the implementation, which will point to the new subview
@interface MyViewController ()
@end
@implementation
UIVisualEffectView *blurEffectView;
...
I have a Tap Gesture recognizer which calls another method to "unblur" by removing the subview that was added
- (void) tapped {
blurEffectView.hidden = true;
[self.view willRemoveSubview:blurEffectView];
}
This method works fine, the blur shows up and covers the view. When the tap happens the blur disappears, and everything looks ok.
Method 2
Next I tried something a little more complex, and it now behaves differently. I created a small Objective-C class to wrap the blur/unblur functions in a separate utility object that I can reuse more easily.
Basically the MyViewController now has a new private variable to reference my new class ViewBlurrer which just extends NSObject. ViewBlurrer now encapsulates the reference to the UIVisualEffectView *blurEffectView, and it's interface has public methods for blur and unblur.
So the hierarchy is something like
MyViewController -> ViewBlurrer -> UIVisualEffectView
ViewBlurrer also maintains a reference to the MyViewController.view, which it uses in the blur and unblur methods. Call this pointer parentView.
This behaves exactly the same for blur, it correctly adds the blur effect that covers up the ViewController's view.
What I observed differently, is that I could not hide and remove the blurEffectView now that it was in this utility class ViewBlurrer. The only way I could make it get removed was to lookup the UIVisualEffectView with arbitrary tag number such as this in the ViewBlurrer.unblur method:
-(void)unblurView {
UIView *theSubView = [self.parentView viewWithTag:66];
theSubView.hidden = YES;
[self.parentView willRemoveSubview:theSubView];
}
My question is why I can't just call [self.parentView willRemoveSubview:blurEffectView], but I have to look up by tag isn't the pointer to blurEffectView that I inserted to the parentView still equivalent as it was in the original approach in Method 1?
Upvotes: 1
Views: 1512
Reputation: 2790
As already mentioned in the comments to your question, you are not supposed to call willRemoveSubview
yourself. It is automatically invoked (by the system) when you remove a subview from the view hierarchy. From the documentation of willRemoveSubview
:
This method is invoked when subview receives a removeFromSuperview() message or subview is removed from the view due to it being added to another view with addSubview(_:).
Hence you should rather write:
- (void) tapped {
blurEffectView.hidden = true;
[blurEffectView removeFromSuperview];
}
or shorter:
- (void) tapped {
[blurEffectView removeFromSuperview];
}
Upvotes: 2