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

在removeFromSuperview方法中使用UIView.animate引发EXC_BAD_ACCESS崩溃求助

问题:重写removeFromSuperview添加动画后触发EXC_BAD_ACCESS崩溃

我给视图控制器的自定义视图添加了带按钮的子视图,点击按钮会调用removeFromSuperview()。我重写了这个方法,用UIView.animate做退场动画,动画完成后调用super.removeFromSuperview(),但运行时出现EXC_BAD_ACCESS错误,相关代码和崩溃日志如下:

@objc func confirmAction() {
    self.removeFromSuperview()
}

override func removeFromSuperview() {
    UIView.animate(withDuration: 0.2) {
        self.bgView.alpha = 0.1
        self.bottomView.frame = CGRectMake(0, self.bounds.height, self.bottomView.frame.width, self.bottomView.frame.height)
    } completion: { finish in
        self.bgView.alpha = 0.1
        self.bottomView.frame = CGRectMake(0, self.bounds.height, self.bottomView.frame.width, self.bottomView.frame.height)
        super.removeFromSuperview()
    }
}

崩溃日志:

EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000951d5b40fb50

Crashed: com.apple.main-thread
0  libobjc.A.dylib                0x1c20 objc_msgSend + 32
1  UIKitCore                      0x4e7c -[UIView bounds] + 32
2  ZYLight                        0x2e0a20 closure #2 in ZYAddDeviceStepView.removeFromSuperview() + 4301179424
3  ZYLight                        0x775fc thunk for @escaping @callee_guaranteed (@unowned Bool) -> () + 4298651132 (<compiler-generated>:4298651132)
4  UIKitCore                      0x104278c __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ + 36
5  UIKitCore                      0xd1280 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 636
6  UIKitCore                      0xd01dc -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 436
7  UIKitCore                      0xcf8fc -[UIViewAnimationState animationDidStop:finished:] + 196
8  UIKit                          0xb1848 -[UIViewAnimationStateAccessibility animationDidStop:finished:] + 172
9  QuartzCore                     0x12dfc CA::Layer::run_animation_callbacks(void*) + 232
10 libdispatch.dylib              0x3f88 _dispatch_client_callout + 20
11 libdispatch.dylib              0x127f4 _dispatch_main_queue_drain + 928
12 libdispatch.dylib              0x12444 _dispatch_main_queue_callback_4CF + 44
13 CoreFoundation                 0x9a6c8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
14 CoreFoundation                 0x7c02c __CFRunLoopRun + 2036
15 CoreFoundation                 0x80eb0 CFRunLoopRunSpecific + 612
16 GraphicsServices               0x1368 GSEventRunModal + 164
17 UIKitCore                      0x3a1668 -[UIApplication _run] + 888
18 UIKitCore                      0x3a12cc UIApplicationMain + 340
19 libswiftUIKit.dylib            0x35308 UIApplicationMain(_:_:_:_:) + 104
20 ZYLight                        0x86c4 main + 4298196676 (ZYLightMeshProtocol.swift:4298196676)
原因分析与解决方案
  • 崩溃原因:
    从崩溃栈可以看到,崩溃发生在动画完成闭包访问self.bounds时。核心问题是:动画闭包强引用了self,当super.removeFromSuperview()执行后,视图已经从父视图移除,若此时视图没有其他强引用就会被内存回收,但闭包仍持有self的无效引用,后续访问self的属性就会触发野指针错误。另外,完成闭包中重复设置动画属性属于冗余操作,增加了出错风险。

  • 修复代码:
    使用弱引用避免循环引用和野指针,同时移除冗余代码:

@objc func confirmAction() {
    self.removeFromSuperview()
}

override func removeFromSuperview() {
    UIView.animate(withDuration: 0.2) { [weak self] in
        guard let self = self else { return }
        self.bgView.alpha = 0.1
        self.bottomView.frame = CGRect(x: 0, y: self.bounds.height, width: self.bottomView.frame.width, height: self.bottomView.frame.height)
    } completion: { [weak self] _ in
        guard let self = self else { return }
        super.removeFromSuperview()
    }
}
  • 额外优化建议:
    • 优先使用自动布局替代直接修改frame:动画时修改约束的constant值,再调用layoutIfNeeded(),适配性更好。
    • 建议新增专用退场动画方法,而非直接重写removeFromSuperview:系统在多种场景下会自动调用该方法(比如父视图被移除时),可能触发意外动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 08:47:39