如何修复Cordova应用在iOS 16.1上崩溃的问题?
我正在开发一款iOS平台的Cordova应用,仅在iOS 16.1系统上会崩溃。我通过以下Swift代码将Cordova的CDViewController子类(SampleController)的WebView作为子视图添加到当前视图控制器中:
// SampleViewController是CDViewController的子类。 if let tempWidgetVC = storyboard.instantiateViewController(withIdentifier: "SampleController") as? SampleController { tempWidgetVC.view.frame = CGRect(x: 0, y: 135, width: self.view.frame.size.width, height: self.view.frame.size.height - 150) self.view.addSubview(tempWidgetVC.webView) }
这段代码在API调用完成后执行时会引发崩溃,但在viewDidLoad或viewDidAppear中执行却完全正常。崩溃日志如下:
thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff0)
frame #0: 0x0000000117237c04 WebKitWebKit::WebUserContentControllerProxy::removeUserMessageHandlerForName(WTF::String const&, API::ContentWorld&) + 804 frame #1: 0x0000000116ed2a54 WebKit-[WKUserContentController removeScriptMessageHandlerForName:] + 52
frame #2: 0x0000000111e350fe BlackBerryDynamics___lldb_unnamed_symbol7713 + 267 frame #3: 0x000000011719ab7f WebKitWebKit::WebProcessPool::~WebProcessPool() + 2569
frame #4: 0x0000000116ecf9a1 WebKit-[WKProcessPool dealloc] + 48 frame #5: 0x00007ff80004b6b1 libobjc.A.dylibobjc_object::sidetable_release(bool, bool) + 203
frame #6: 0x00000001171a4b43 WebKitWebKit::WebProcessProxy::~WebProcessProxy() + 2389 frame #7: 0x00000001171a4c4e WebKitWebKit::WebProcessProxy::~WebProcessProxy() + 14
frame #8: 0x0000000116cdf39d WebKitWTF::ThreadSafeRefCounted<WebKit::AuxiliaryProcessProxy, (WTF::DestructionThread)2>::deref() const + 67 frame #9: 0x00000001171afb38 WebKitWTF::Detail::CallableWrapper<WebKit::WebPageProxy::close()::$_13, void>::~CallableWrapper() + 136
frame #10: 0x00000001140878f8 JavaScriptCoreWTF::RunLoop::performWork() + 440 frame #11: 0x00000001140881da JavaScriptCoreWTF::RunLoop::performWork(void*) + 26
frame #12: 0x00007ff800387035 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 frame #13: 0x00007ff800386f74 CoreFoundation__CFRunLoopDoSource0 + 157
frame #14: 0x00007ff800386771 CoreFoundation__CFRunLoopDoSources0 + 212 frame #15: 0x00007ff800380e73 CoreFoundation__CFRunLoopRun + 927
frame #16: 0x00007ff8003806f7 CoreFoundationCFRunLoopRunSpecific + 560 frame #17: 0x00007ff809c5c28a GraphicsServicesGSEventRunModal + 139
frame #18: 0x000000011f36562b UIKitCore-[UIApplication _run] + 994 frame #19: 0x000000011f36a547 UIKitCoreUIApplicationMain + 123
frame #20: 0x00000001109e2c72 libswiftUIKit.dylibUIKit.UIApplicationMain(Swift.Int32, Swift.Optional<Swift.UnsafeMutablePointer<Swift.UnsafeMutablePointer<Swift.Int8>>>, Swift.Optional<Swift.String>, Swift.Optional<Swift.String>) -> Swift.Int32 + 98 frame #21: 0x000000010f805c55 OCPMobilemain [inlined] generic specialization <App.AppDelegate> of static __C.UIApplicationDelegate.main() -> () at UserDefaultsHelper.swift:0 [opt]
frame #22: 0x000000010f805c05 OCPMobilemain [inlined] static OCPMobile.AppDelegate.$main() -> () at <compiler-generated>:11:1 [opt] frame #23: 0x000000010f805bf4 OCPMobilemain at UserDefaultsHelper.swift:0 [opt]
frame #24: 0x000000010ffeb2bf dyld_simstart_sim + 10 frame #25: 0x0000000113f8852e dyldstart + 462
问题根源
崩溃日志指向WebKit尝试访问已销毁的对象(EXC_BAD_ACCESS),核心原因是:API回调执行完后,tempWidgetVC作为临时变量被ARC自动释放,但其关联的WebKit资源(WKProcessPool、WKUserContentController等)还在后台处理操作,导致访问已释放内存。
而viewDidLoad/viewDidAppear中正常是因为控制器生命周期阶段的ARC引用时机特殊,临时变量的生命周期被意外延长,属于侥幸情况,并非正确实现。
解决方案
- 持有子控制器的强引用
在当前视图控制器中添加属性,保留SampleController实例,避免被ARC回收:
// 在当前控制器类中声明强引用属性 var widgetVC: SampleController? // API回调中执行的代码 if let tempWidgetVC = storyboard.instantiateViewController(withIdentifier: "SampleController") as? SampleController { tempWidgetVC.view.frame = CGRect(x: 0, y: 135, width: self.view.frame.size.width, height: self.view.frame.size.height - 150) // 正确建立父子控制器关系 self.addChild(tempWidgetVC) self.view.addSubview(tempWidgetVC.webView) tempWidgetVC.didMove(toParent: self) // 持有引用 self.widgetVC = tempWidgetVC }
遵循UIViewController生命周期规范
Cordova的CDViewController依赖完整的控制器生命周期,直接添加webView会跳过viewWillAppear、didMoveToParent等关键方法,导致WebKit资源初始化/销毁流程异常,必须通过addChild和didMove(toParent:)完成父子关系绑定。适配iOS 16.1的严格内存检查
iOS 16.1对WebKit的内存管理做了更严格的校验,之前版本未触发的内存问题在该版本暴露,确保所有WebKit相关的控制器和资源都有完整的引用链。
内容的提问来源于stack exchange,提问作者suraj Gupta

