iOS开发基础72-Xcode 7 升级后的问题与解决方案详解
在 iOS 开发中,Xcode 的重大版本升级通常会带来不少变化。本文探讨了开发者在从 Xcode 6 升级到 Xcode 7 后遇到的一些问题,主要聚焦于状态栏(StatusBar)的管理和配置,并提供详细的解决方案和背后的底层逻辑分析。
问题一:老项目在 Xcode 7 上崩溃
在 Xcode 6 上运行正常的老项目在 Xcode 7 上运行直接崩溃。经过分析发现,问题主要源于窗口管理的方式变更。
症状:在 Xcode 7 中,如果一个窗口(Window)没有根视图控制器(rootViewController),则会引发崩溃。
解决方案
对于之前用于处理 TableView 滚回顶部的 topWindow,只需设置一个根视图控制器即可解决此问题。
UIWindow *topWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
topWindow.rootViewController = [UIViewController new];
// 处理 TableView 滚回顶部的逻辑放在新的根视图控制器中。
通过为 topWindow 设置一个 rootViewController,确保其有根视图控制器,从而避免崩溃。
问题二:状态栏不可见
设置了 topWindow 的 rootViewController 后,发现状态栏消失了,并且在当前视图控制器中设置状态栏显示和颜色无效。
症状:iOS 9 中,状态栏的显示与隐藏由最顶层窗口(Window)的根视图控制器决定。
解决方案
- 在根视图控制器中显示状态栏:
- (BOOL)prefersStatusBarHidden {
return NO; // 保持状态栏显示
}
- 设置状态栏样式:
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault; // 设置状态栏样式
}
通过在顶层窗口的根视图控制器中设置状态栏属性,可以解决状态栏显示和样式的问题。
问题三:从一个控制器弹出或推送另一个控制器时状态栏问题
当通过 modal 或 push 弹出新的视图控制器时,状态栏的颜色和隐藏状态无法按预期修改。这是因为状态栏的管理权由顶层窗口的根视图控制器决定。
解决方案
方案一:使用通知
通过通知机制在不同控制器之间传递状态栏的设置参数。
方案二:使用单例(推荐)
使用单例模式设计 topWindow,并提供两个属性:
@interface TopWindowController : UIViewController
@property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
@property (nonatomic, assign) BOOL statusBarHidden;
@end
@implementation TopWindowController
- (BOOL)prefersStatusBarHidden {
return self.statusBarHidden;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return self.statusBarStyle;
}
- (void)setStatusBarHidden:(BOOL)statusBarHidden {
_statusBarHidden = statusBarHidden;
[self setNeedsStatusBarAppearanceUpdate];
}
- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle {
_statusBarStyle = statusBarStyle;
[self setNeedsStatusBarAppearanceUpdate];
}
@end
通过单例模式,确保 topWindow 只有一个实例,并提供统一的接口来控制状态栏的显示和样式。
iOS 版本变化带来的©ATTENTION:
在 iOS 6 到 iOS 8 期间,状态栏样式通常由应用程序级别管理,这可以通过在 Info.plist
中设置 UIViewControllerBasedStatusBarAppearance
为 NO
来实现。这样,UIApplication 会统一管理状态栏。
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
iOS 9 之后的变化
Documentation状态栏管理的变更:iOS 9 开始,苹果不再推荐通过 UIApplication 设置状态栏,建议将 UIViewControllerBasedStatusBarAppearance
设置为 YES
(或删除该配置,因为默认值为 YES)。
这意味着状态栏的管理权转交给顶层窗口的根视图控制器。在多窗口应用中,如果其他窗口显示级别高于主窗口,状态栏的管理权将自动转移到最顶层的窗口根视图控制器。
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
总结
在从 Xcode 6 升级到 Xcode 7 的过程中,开发者需要注意状态栏管理方式的变化。通过分析和解决实际问题,提供了以下几点建议:
- 确保每个窗口都有根视图控制器:避免因 lack of rootViewController 导致的崩溃。
- 在顶层窗口的根视图控制器中配置状态栏:管理状态栏的显示和样式。
- 使用单例模式统一管理 topWindow:可扩展性高,代码简洁且清晰。