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统一管理,可以调整调用逻辑:
- 修改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 } }
- 更新Objective-C++包装类,让方法返回UIWindow实例:
@implementation MyObjCppWrapper + (UIWindow*)mySampleObjCppFunc { return [MySampleCreateWindow CreateWindow]; } @end
- 在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
相关产品推荐
相关产品推荐

