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

Swift项目通过OC++桥接创建UIWindow出现外观过渡调用失衡问题

解决iOS中通过Objective-C++桥接创建UIWindow导致的外观过渡不平衡问题

问题根源

你碰到的Unbalanced calls to begin/end appearance transitions for <UINavigationController: ...>错误,核心原因是UIWindow的生命周期过短:

  • 在CreateWindow方法里创建的window是局部变量,方法执行完毕后会被ARC自动释放
  • 此时UINavigationController的外观过渡流程还未完成,窗口被销毁后就会触发这个过渡不平衡的错误
  • 直接把代码放到AppDelegate的didFinishLaunching里能正常运行,是因为此时window会被赋值给AppDelegate的实例变量(或系统默认属性),生命周期被延长,过渡流程能完整执行

修复方案

方案1:给UIWindow添加类级强引用(最简方案)

修改MySampleCreateWindow类,将window定义为类属性,通过强引用避免被提前释放:

@objc
class MySampleCreateWindow: NSObject {
    // 类属性保存window,延长生命周期
    @objc static var window: UIWindow?
    
    @objc
    static func CreateWindow () {
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = UINavigationController(rootViewController: ViewController())
        window?.makeKeyAndVisible()
    }
}

方案2:将Window管理权交回AppDelegate

如果希望窗口的生命周期由AppDelegate统一管理,可以调整调用逻辑:

  1. 修改Swift类,让CreateWindow返回创建好的UIWindow:
@objc
class MySampleCreateWindow: NSObject {
    @objc
    static func CreateWindow () -> UIWindow {
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.rootViewController = UINavigationController(rootViewController: ViewController())
        return window
    }
}
  1. 更新Objective-C++包装类,让方法返回UIWindow实例:
@implementation MyObjCppWrapper

+ (UIWindow*)mySampleObjCppFunc {
    return [MySampleCreateWindow CreateWindow];
}

@end
  1. 在AppDelegate中持有Window引用:
class AppDelegate: UIResponder, UIApplicationDelegate {
    // 声明window属性,强引用持有
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        NSLog("didFinishLaunching called")
        window = MyObjCppWrapper.mySampleObjCppFunc()
        window?.makeKeyAndVisible()
        return true
    }
}

iOS 13+适配补充

如果项目需要适配iOS 13及以上,官方推荐使用SceneDelegate管理UIWindow,需在scene(_:willConnectTo:options:)方法中处理窗口创建,同样要保证window被SceneDelegate的属性持有,避免局部变量被释放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:40:47