又到一年一度的大迭代时间了。这几天终于抽出时间,把Xcode升级到11了,才发现今年的坑不是一般的多啊!
现在捡一些重要的小结一下,未总结完全的,欢迎评论补充!
1、presentViewController的modalPresentationStyle问题:
首先我们查看一下UIModalPresentationStyle,对比以前的看看有什么变化没有。发现新增了一个枚举值UIModalPresentationAutomatic,默认的就是这个,所以才会弹出不是全屏的界面。
typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
UIModalPresentationFullScreen = 0,
UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2,
};
如果我们想修改为以前全屏的效果的话,方法有两个:
(1)、修改modalPresentationStylew为UIModalPresentationFullScreen;
(2)、不用presentViewController这种方法,条条大路通罗马,你这种变了,那我就换一种,用navigationController的pushViewController;
注意:presentViewController默认的UIModalPresentationAutomatic推出新的VC的时候,原VC不会调用viewWillDisappear与viewDidDisappear方法;退出新VC时,原VC不会调用viewWillAppear与viewDidAppear方法。
eg:vcA presentViewController vcB
vcA->vcB:vcA不会调用viewWillDisappear与viewDidDisappear方法;
vcB->vcA:vcA不会调用viewWillAppear与viewDidAppear方法;
2、私有方法KVC不能随便玩了
在 iOS 13 中不再允许使用valueForKey、setValue:forKey: 等方法获取或设置私有属性,虽然编译可以通过,但是在运行时会直接崩溃。
我一直做项目的原则是,尽量使用简单易懂的代码,这个比使用一堆看上去更高深的底层代码要更不容易,除了必需之外,能用简单方法实现的
//[countTextField setValue:[PXColorManager textColorFour] forKeyPath:@"_placeholderLabel.textColor"];
//替换为
countTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:Localized(@"inputCount", nil) attributes:@{NSForegroundColorAttributeName:[PXColorManager textColorFour],NSFontAttributeName:FontPingFangSCRegular(16)}];
//[countTextField setValue:FontPingFangSCRegular(16) forKeyPath:@"_placeholderLabel.font"];
UITextField 的私有属性 _placeholderLabel 被禁止访问
3、UISegmentedControl 默认样式改变
默认样式变为白底黑字,如果设置修改过颜色的话,页面需要修改。
原本设置选中颜色的 tintColor 已经失效,新增了 selectedSegmentTintColor 属性用以修改选中的颜色。
4、UIWebView被废弃
"No longer supported; please adopt WKWebView.", ios(2.0, 12.0)
5、iOS 13 需增加蓝牙权限描述
如果你的应用需要使用蓝牙权限,需要在Info.plist
里面加上NSBluetoothAlwaysUsageDescription
这个key
,对应的描述value
根据权限的用途来描述即可。
6、iOS 13 DeviceToken有变化,推送的 deviceToken 获取到的格式发生变化
原本可以直接将 NSData 类型的 deviceToken 转换成 NSString 字符串,然后替换掉多余的符号即可:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *token = [deviceToken description]; for (NSString *symbol in @[@" ", @"<", @">", @"-"]) { token = [token stringByReplacingOccurrencesOfString:symbol withString:@""]; } NSLog(@"deviceToken:%@", token); }
在 iOS 13 中,这种方法已经失效,NSData类型的 deviceToken 转换成的字符串变成了:
{length = 32, bytes = 0xd7f9fe34 69be14d1 fa51be22 329ac80d ... 5ad13017 b8ad0736 }
需要进行一次数据格式处理,参考友盟的做法,可以适配新旧系统,获取方式如下:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { if (![deviceToken isKindOfClass:[NSData class]]) return; const unsigned *tokenBytes = [deviceToken bytes]; NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x", ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]), ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]), ntohl(tokenBytes[6]), ntohl(tokenBytes[7])]; NSLog(@"deviceToken:%@", hexToken); }
7、MPMoviePlayerController 在iOS 13已经不能用
在iOS 9之前播放视频可以使用MediaPlayer.framework 中的MPMoviePlayerController类来完成,它支持本地视频和网络视频播放。但是在 iOS 9 开始被弃用,如果在 iOS 13 中继续使用的话会直接抛出异常:
这个没啥好说的,既然不能再用了,那只能换掉了。替代方案就是AVPlayer,IJKPlayer就是了
8、Sign in with Apple (提供第三方登录的注意啦
如果你的应用使用了第三方登录,那么你可能也需要加下 「Sign in with Apple」,目前苹果只在 News and Updates 上提到正式发布时要求加上,具体发布时间还没确定。
Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.
9、即将废弃的 LaunchImage
iOS 8 之前我们是在LaunchImage 来设置启动图,但是随着苹果设备尺寸越来越多,我们需要在对应的 aseets 里面放入所有尺寸的启动图,这是非常繁琐的一个步骤。因此在 iOS 8 苹果引入了 LaunchScreen.storyboard,支持界面布局用的 AutoLayout + SizeClass ,可以很方便适配各种屏幕。
需要注意的是,苹果在 Modernizing Your UI for iOS 13 section 中提到,从2020年4月开始,所有支持 iOS 13 的 App 必须提供 LaunchScreen.storyboard,否则将无法提交到 App Store 进行审批。
10、顶部状态栏、底部导航栏的适配:样式改变,位置改变
之前 Status Bar 有两种状态,default 和 lightContent
现在 Status Bar 有三种状态,default, darkContent 和 lightContent
现在的 darkContent 对应之前的 default,现在的 default 会根据情况自动选择 darkContent 和 lightContent
11、直接给 textfield.leftView 赋值一个 UILabel 对象,他的宽高会被 sizeToFit,而不是创建时的值。
解决方法:嵌套一个UIView
12、Xcode 11 创建的工程在低版本设备上运行黑屏
使用 Xcode 11 创建的工程,运行设备选择 iOS 13.0 以下的设备,运行应用时会出现黑屏。这是因为 Xcode 11 默认是会创建通过 UIScene 管理多个 UIWindow 的应用,工程中除了 AppDelegate 外会多一个 SceneDelegate.
这是为了 iPadOS 的多进程准备的,也就是说 UIWindow 不再是 UIApplication 中管理。但是旧版本根本没有 UIScene,因此解决方案就是在 AppDelegate 的头文件加上:
@property (strong, nonatomic) UIWindow *window;