You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS跨类调用willRemoveSubview无法移除子视图的原因咨询

问题分析与解决方案

首先要纠正一个关键误解:willRemoveSubview: 根本不是用来移除子视图的API!这是UIView的生命周期回调方法,当某个子视图即将被从父视图中移除时,系统会自动调用父视图的这个方法,通知父视图“我要移除这个子视图了”。开发者主动调用它不会产生任何移除视图的效果——你之前在ViewController里觉得“正常移除”,其实是因为设置了hidden = true让视图隐藏,和willRemoveSubview:没有半毛钱关系。

接下来分析你遇到的跨类指针失效问题,主要有两个核心原因:

1. 工具类中的blurEffectView指针并非指向父视图中存在的那个实例

你在ViewBlurrer类里封装了blurEffectView和parentView,但可能出现以下情况:

  • 指针被重新赋值:比如多次调用模糊方法时,工具类每次都创建了新的UIVisualEffectView实例,但没有更新blurEffectView的引用,导致它指向的是旧的、已经被移除或者根本没被添加到父视图的实例。这时候你调用[self.parentView willRemoveSubview:blurEffectView],本质是在通知父视图“要移除一个不在我层级里的视图”,自然毫无作用。
  • 引用类型错误:如果blurEffectView是弱引用(weak),而没有被其他强引用持有,它可能已经被ARC自动释放,指针变成nil。这时候调用任何方法都不会有效果。

2. 你混淆了“隐藏视图”和“移除视图”的区别

在ViewController的代码里,你设置了blurEffectView.hidden = true,这只是让视图不可见,但它仍然存在于父视图的层级结构中。而你可能误以为这是“移除”,但到了工具类里,你期望的是真正把视图从父视图层级中删掉,但却依然用hidden+错误的willRemoveSubview:组合,自然达不到预期。

正确的解决方法

第一步:改用正确的移除API

要真正移除子视图,应该调用:

[blurEffectView removeFromSuperview];

这个方法会把视图从父视图的层级中彻底移除,同时系统会自动调用父视图的willRemoveSubview:和didRemoveSubview:回调。

第二步:确保工具类持有正确的实例引用

在ViewBlurrer类中:

  • 用强引用(strong)持有blurEffectView,确保它不会被ARC意外释放:
    @interface ViewBlurrer ()
    @property (nonatomic, strong) UIVisualEffectView *blurEffectView;
    @property (nonatomic, weak) UIView *parentView; // 父视图用weak避免循环引用
    @end
    
  • 在模糊方法中,检查是否已经存在blurEffectView,如果存在就不要重复创建:
    - (void)blurView {
        if (self.blurEffectView) {
            self.blurEffectView.hidden = NO;
            return;
        }
        UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
        self.blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
        self.blurEffectView.frame = self.parentView.bounds;
        self.blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        // 可选:设置tag作为兜底方案
        self.blurEffectView.tag = 66;
        [self.parentView addSubview:self.blurEffectView];
    }
    
  • 在取消模糊的方法中,直接使用持有的指针操作:
    - (void)unblurView {
        // 如果只是隐藏视图,用这个:
        // self.blurEffectView.hidden = YES;
        // 如果要彻底从层级移除,用这个:
        [self.blurEffectView removeFromSuperview];
        self.blurEffectView = nil; // 移除后清空引用,下次模糊会重新创建
    }
    

关于指针等价性的问题

只要工具类中的blurEffectView指针确实指向的是被添加到parentView的那个实例,它和ViewController中直接持有的指针是完全等价的——OC中的指针就是指向内存中对象的地址,只要地址正确,跨类使用没有任何问题。出现差异的原因绝对不是“跨类”本身,而是指针指向的对象不对,或者你用错了API。

内容的提问来源于stack exchange,提问作者ammianus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:51:39