IOS window.rootViewController 切换原rootViewController无法释放(问题解决)

本文记录了一次在iOS开发中遇到的奇怪问题:一个界面通过消息通知刷新数据时出现内存泄露。作者通过排除法和代码审查,最终定位到UIViewController扩展处理中的问题,涉及rootViewController切换时的内存管理。

先说一下问题吧,今天遇到了一个奇怪的问题。一个界面通过消息通知刷新数据,断点跑了2次,感觉很奇怪。通过和公司小伙伴沟通发现是由于退出登录后再登录进去后发现此问题。我首先想到的就是此功能界面没有释放,但是查看界面处理没有特殊操作。里面想到就是因为切换rootViewController的时候原rootViewController没有释放掉。查看了原 rootViewController界面A,在发现界面A并没有其他原因导致其有可能不被释放。
立即想到了自己做的UIViewController 的扩展处理中有问题,把扩展去掉后释放正常。
先附上我切换rootViewController 的代码如下(代码中忽略我的其他操作)

+(void)setRootViewViewController:(UIViewController *)controller{
   UIWindow * window = [UIApplication sharedApplication].delegate.window;
   //清空root
   if (window.rootViewController){
       window.rootViewController = nil;
   }
   
   UINavigationController * navTabBar = [[UINavigationController alloc] initWithRootViewController:controller];
   window.rootViewController = navTabBar;
   system_titleStatusBarHeight   = [[UIApplication sharedApplication] statusBarFrame].size.height;
   system_titleViewHeight        = navTabBar.navigationBar.frame.size.height + system_titleStatusBarHeight;
   controller.automaticallyAdjustsScrollViewInsets = NO;
   if ([controller isKindOfClass:[UITabBarController class]]) {
       system_tabbarHeight = ((UITabBarController *)controller).tabBar.frame.size.height;
   }
   [JLBRouter manager].navigationVC = navTabBar;
}

在分析扩展代码中并没有发现导致没有释放的原因是我调用了
self.navigationController.presentationController 。
什么鬼东西,这也都可以????

在这里插入图片描述
在这里做一个记录吧,希望给大家一个提示。

这段代码实现了一个 **基于 `UISplitViewController` 的主从视图(Master-Detail)应用**,适用于 iPad 或支持多任务的 iPhone 设备。以下是详细解析: --- ### **代码结构** 1. **`AppDelegate`** - 作为应用入口,负责初始化窗口和根视图控制器。 - 实现了 `UIApplicationDelegate` 协议,处理应用启动逻辑。 2. **`UISplitViewController` 配置** - 设置主从视图控制器(`MasterController` 和 `DetailController`)。 - 通过 `UINavigationController` 包装,支持导航栏操作。 3. **`UISplitViewControllerDelegate` 扩展** - 实现 `collapseSecondary` 方法,控制从视图在紧凑模式下的折叠行为。 --- ### **关键步骤** #### 1. 初始化主从控制器 ```swift let masterController = MasterController() let masterNavigationController = UINavigationController(rootViewController: masterController) let detailController = DetailController() let detailNavigationController = UINavigationController(rootViewController: detailController) ``` - **`MasterController`**:主视图(如列表或菜单)。 - **`DetailController`**:从视图(如选中项的详细信息)。 - 分别用 `UINavigationController` 包装,支持导航栏和栈操作。 #### 2. 配置 `UISplitViewController` ```swift let splitViewController = UISplitViewController() splitViewController.viewControllers = [masterNavigationController, detailNavigationController] splitViewController.preferredDisplayMode = .oneBesideSecondary splitViewController.delegate = self ``` - **`viewControllers`**:设置主从控制器数组(顺序决定左右布局)。 - **`preferredDisplayMode`**:默认显示模式为 **主从并排**(`.oneBesideSecondary`)。 - **`delegate`**:设置代理以处理折叠逻辑。 #### 3. 调整布局参数 ```swift splitViewController.preferredPrimaryColumnWidthFraction = 0.5 splitViewController.maximumPrimaryColumnWidth = 2000 ``` - **`preferredPrimaryColumnWidthFraction`**:主视图宽度占比(默认 0.5,即 50%)。 - **`maximumPrimaryColumnWidth`**:主视图最大宽度(2000 表示几乎无限制)。 #### 4. 设置根视图控制器 ```swift self.window = UIWindow(frame: UIScreen.main.bounds) self.window!.rootViewController = splitViewController self.window!.makeKeyAndVisible() ``` - 创建窗口并设置 `splitViewController` 为根控制器,显示应用界面。 #### 5. 实现代理方法 ```swift func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { return true } ``` - **作用**:在紧凑模式(如 iPhone 竖屏)下,决定是否折叠从视图到主视图。 - **`return true`**:始终折叠从视图(即默认显示主视图)。 --- ### **潜在问题与优化** 1. **`maximumPrimaryColumnWidth` 过大** - 2000 的值可能导致主视图过宽,建议根据设备尺寸动态计算: ```swift splitViewController.maximumPrimaryColumnWidth = UIScreen.main.bounds.width * 0.6 ``` 2. **缺少深色模式/本地化支持** - 界面文本或颜色未适配系统设置,可通过 `UIUserInterfaceStyle` 和 `NSLocalizedString` 改进。 3. **代理方法逻辑简化** - 当前 `collapseSecondary` 直接返回 `true`,可能需根据业务逻辑判断是否折叠(如仅在无选中项时折叠)。 4. **Swift 5.7+ 的 `SceneDelegate`** - 现代 iOS 项目通常使用 `SceneDelegate` 管理窗口,建议迁移(若支持 iOS 13+)。 --- ### **完整优化示例** ```swift import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let masterController = MasterController() let masterNav = UINavigationController(rootViewController: masterController) let detailController = DetailController() let detailNav = UINavigationController(rootViewController: detailController) let splitVC = UISplitViewController() splitVC.viewControllers = [masterNav, detailNav] splitVC.preferredDisplayMode = .oneBesideSecondary splitVC.delegate = self splitVC.preferredPrimaryColumnWidthFraction = 0.3 // 更窄的主视图 splitVC.maximumPrimaryColumnWidth = 320 // 适配 iPad 分屏 window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = splitVC window?.makeKeyAndVisible() return true } } extension AppDelegate: UISplitViewControllerDelegate { func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { // 仅在无选中项时折叠从视图 if let master = primaryViewController as? UINavigationController, let masterVC = master.topViewController as? MasterController { return masterVC.selectedItem == nil } return false } } ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值