原文同步发布在:devhy.com/33-xcode11-…ios
一年一适配,今年又来了。
今年总体上问题不大,我司的App 没有出现编译报错问题。git
首先,用 Xcode10 编译的 App 在 iOS 13 上使用甚至几乎完美😀
然而,用 Xcode11 编译的 App 再在 iOS 13 上跑,就有些问题了😂github
具体碰到的问题以下:shell
iOS 13 多了一个新的枚举类型 UIModalPresentationAutomatic
,且是modalPresentationStyle
的默认值。xcode
UIModalPresentationAutomatic
实际是表现是在 <iOS 13 的设备上被映射成UIModalPresentationFullScreen
,在 >=iOS 13的设备上被映射成UIModalPresentationPageSheet
。ruby
我这边的设计师表示,新样式不错,能够不用改😆。bash
不过, PageSheet
与 FullScreen
对比 有个须要注意的地方,控制器的生命周期有点区别:markdown
以 控制器A
、控制器B
举例:app
控制器A
present 控制器B
控制器A
不会调用 viewWillDisappear
以及 viewDidDisappear
控制器B
dismiss 时 控制器A
不会调用 viewWillAppear
以及 viewDidAppear
那么若是有些业务逻辑会在控制器A
的生命周期里作的话,就须要考虑其余方式实现,或者改回UIModalPresentationFullScreen
ide
若是须要改为本来全屏的样式,能够处理Controller:
modalPresentationStyle
值modalPresentationStyle
值modalPresentationStyle
的get方法扩展 看上面gif,用户是能够经过手势下拉关闭被present出来的控制器的,那若是我须要禁止他下来要怎么实现呢?
能够参考 disabling_pulling_down_a_sheet 的Demo
设置presentationController.delegate
代理对象,实现 UIAdaptivePresentationControllerDelegate
协议方法
@interface XXViewController () <UIAdaptivePresentationControllerDelegate> @property (nonatomic, assign) BOOL allowBack; @end @implementation XXViewController - (void)viewDidLoad { [super viewDidLoad]; // ... // 若是vc被navigation套了一层就要取navigation的presentationController self.navigationController.presentationController.delegate = self; } // 使用UIAdaptivePresentationControllerDelegate 协议方法控制可否下拉dismiss // 或者不实现这个协议,设置self.modalInPresentation(YES-不容许下拉关闭,NO-能够下拉关闭) - (BOOL)presentationControllerShouldDismiss:(UIPresentationController *)presentationController { return self.allowBack; } // 若是 self.modalInPresentation=YES 或者 // 上面协议方法return NO,用户再下拉就会在这收到回调 - (void)presentationControllerDidAttemptToDismiss:(UIPresentationController *)presentationController { // 若是self.allowBack == NO,会回调到这里 // 能够在这里作一些事情而后再考虑让 self.allowBack=YES 或 // 则让 self.modalInPresentation=NO 便可让页面能够下拉返回 } @end 复制代码
以下方式,直接给 textfield.leftView
赋值一个 UILabel
对象,他的宽高会被 sizeToFit
,而不是建立时的值。
// left view label UILabel *phoneLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 63, 50)]; phoneLabel.text = @"手机号"; phoneLabel.font = [UIFont systemFontOfSize:16]; // set textfield left view self.textfieldName.leftView = phoneLabel; 复制代码
如所看到,实际 leftview 的width为59,height为19:
经过监听 leftView
的 frame
变化,发现是 layoutSubview
以后变化的。 最终仍是给UILabel多套了一个UIView来解决
// label UILabel *phoneLabel = [[UILabel alloc] init]; phoneLabel.text = @"手机号"; phoneLabel.font = [UIFont systemFontOfSize:16]; [phoneLabel sizeToFit]; phoneLabel.centerY = 50/2.f; // left view UIView *leftView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 63, 50}]; [leftView addSubview:phoneLabel]; // set textfield left view self.textfieldName.leftView = leftView; 复制代码
打开有UISearchBar
的页面发现Crash了,看到控制台输出提示:
// 获取_searchField
UITextField *sField = [self.searchbar valueForKey:@"_searchField"];
// crash log
*** Terminating app due to uncaught exception 'NSGenericException', reason:
'Access to UISearchBar's _searchField ivar is prohibited.
This is an application bug'
复制代码
看起来是禁止访问私有属性了。
用 Xcode 10 编译的 App 在 iOS 13 上能正常使用,那么就是 Xcode 11 作了限制访问私有属性的一些处理了。
偶然发现 iOS 13 中增长了UISearchTextField
类,且暴露了searchTextField
。
// UISearchTextField.h UIKIT_CLASS_AVAILABLE_IOS_ONLY(13.0) @interface UISearchTextField : UITextField // ... @end @interface UISearchBar (UITokenSearch) @property (nonatomic, readonly) UISearchTextField *searchTextField; @end 复制代码
可是仅在 iOS 13 以上系统支持,仍是暂时用遍历view的方式去作了😂
点击导航栏返回的时候Crash了,控制台输出提示:
Теrmіnаtіng арр due to uncaught exception' NSInternalInconsistencyException' , reason : ' Override of -navigationBar : shouldPopItem: returned YES after manually popping a view controller ( navigat ionController=<MHCRNavgationController : 0x106039400>) ' 复制代码
由于咱们工程里,基本上全部的 Controller
是继承基类 BaseViewController
并实现- (BOOL)naviBack:
方法,用于实如今用户点击返回和策划返回时,一些不能返回的特殊处理。 其根本原理是经过实现 UINavgationBar
的代理方法 - (BOOL)navigationBar:shouldPopItem:
来作的控制:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { // 默承认以返回 BOOL canGoBack = YES; // BaseViewController定义协议方法判断可否能点击返回上一层 UIViewController *vc = self.viewControllers.lastObject; if ([vc isKindOfClass:BaseViewController.class]) { canGoBack = [(BaseViewController *)vc naviBack:nil]; } if (canGoBack) { [self popViewControllerAnimated:YES]; } return canGoBack; } 复制代码
可是我实现的时候有 Return YES
啊!想了想,试着 注释 了[self popViewControllerAnimated:YES]
,发现没有崩溃了。 可是在iOS 12上,会发现控制器没有回到上一层,如图,只有navbar回到上一层了:
好吧,那只能判断一下版本解决这个问题了,修改方式:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { // 判断 iOS 版本低于13 BOOL bellow13 = !@available(iOS 13.0, *); // 默承认以返回 BOOL canGoBack = YES; // BaseViewController定义协议方法判断可否能点击返回上一层 UIViewController *vc = self.viewControllers.lastObject; if ([vc isKindOfClass:BaseViewController.class]) { canGoBack = [(BaseViewController *)vc naviBack:nil]; } if (canGoBack && bellow13) { // 若是低于13且能够返回,就执行popViewController [self popViewControllerAnimated:YES]; } return canGoBack; } 复制代码
WWDC 19 直播的时候看到夜间模式,老实说挺开心的,直到我用 Xcode 11 开始作适配,妈耶!x N
注意:使用 Xcode 10 编译的 App 依然是日间模式,不会产生效果!!!
初步扫了一下出现的问题以下图,大体状况是:没有设置背景色的系统控件会被设置成黑色,部分控件是tintColor没设置的话也会被改。
因为Assets里的Color配置是 iOS 12 以上才能使用的,因此若是没有作全局主题色设计且须要支持 iOS 12 如下设备,改起来会比较恶心。
对此现象,找设计师沟通。设计师表示,暂时没有精力作夜间模式规划。
设计师问:可否强制只日间模式?
答:能。配置方式有两种,单页面配置
和 全局配置
。
单页配置
将须要配置的 UIViewControler
对象的 overrideUserInterfaceStyle
属性设置成 UIUserInterfaceStyleLight
或者 UIUserInterfaceStyleDark
以强制是某个页面显示为 浅/深色模式
全局配置
在工程的 Info.plist
的中,增长/修改 UIUserInterfaceStyle
为 UIUserInterfaceStyleLight
或 UIUserInterfaceStyleDark
。
2019.07.26 补充: 早上恰好看到知识小集发了篇 适配 Dark Mode 的文章,看了下挺好的,推荐阅读。
推 Cocoapods 私有库校验的时候,收到一个报错:
- ERROR | [iOS] unknown: Encountered an unknown error (Could not find aiossimulator
(valid values: ). Ensure that Xcode -> Window -> Devices has at least
oneiossimulator listed or otherwise add one.) during validation.
复制代码
直觉告诉我是 cocoapods 的问题,去其 github 仓库的 issues 搜了一下,没有搜到 xcode 11 相关的,而后去 google 了一下,看到了这个问题:
cocoapods-cant-find-simulators-pod-repo-push-fails
里面有一条
After installing Xcode 11, pod lib lint is broken again because of fourflusher - The "availability" key from
xcrun simctl list -j
is now a boolean "isAvailable"
可是这个fourflusher的路径我找不到,可能本身的ruby环境不太同样,那么gem会不会支持反查一个工具的位置呢?
经过 gem help
看了下使用说明,发现能够用gem help commands
查找全部gem的指令。 其中就有一个which
指令,描述上说是用来找库文件位置的。
# 使用gem which来查找位置 gem which fourflusher 复制代码
果真出现了:
/Users/HY/.rvm/gems/ruby-2.4.1/gems/fourflusher-2.2.0/lib/fourflusher.rb
复制代码
对应的知道 fourflusher
的位置,那么接下来就能够修改了。
/Users/HY/.rvm/gems/ruby-2.4.1/gems/fourflusher-2.2.0/lib/fourflusher/
find.rb
device['availability'] == '(available)'
device['isAvailable'] == true
便可修改结果如图便可: