iOS开发-适配iOS13

又到了一年一度适配iOS新系统的时候了。这个时候适配好像有点晚,正式版都发布了,才来适配。。。beta发布的时候干嘛去了!!

+[_LSDefaults sharedInstance] 崩溃问题

问题详情

应用在iOS13中跑起来之后,大概过个10s-15s之后,就会崩溃,看显示的崩溃信息就是+[_LSDefaults sharedInstance]这个方法找不到。

看了一下好像是友盟的锅。。然后去友盟看了一下,好像7月4号就更新了一个版本-v6.0.5 应该是解决了这个问题。

  • v6.0.5(更新日期:2019年7月4日)
    • 修复非组件化版本升级导致小概率崩溃问题。

解决方案

实测升级一下sdk,这个问题就解决了。

私有KVC方法

问题详情

已知的问题是在UITextField和UISearchBar中使用私有的KVC方法时会发生问题。

当你使用UITextField,通过KVC私有方法来修改他的placeholder颜色时,下边代码会出现崩溃的问题:

1
[self.myTextField setValue:[UIColor textColor] forKeyPath:@"_placeholderLabel.textColor"];

会出现崩溃问题:

1
Trapped uncaught exception 'NSGenericException', reason: 'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug'

同样的,在修改UISearchBar的_searchField时也会有这种问题崩溃。

解决方案

这个问题一共有两种解决方案。
一个是简单粗暴,直接把下划线去掉。

1
[self.myTextField setValue:[UIColor textColor] forKeyPath:@"placeholderLabel.textColor"];

还有一种是通过设置attributedPlaceholder来设置。

1
2
3
NSDictionary *attributedDic = @{NSForegroundColorAttributeName:[UIColor textColor]};
NSMutableAttributedString *placeholderAttributedString = [[NSMutableAttributedString alloc] initWithString:placeholderString attributes:attributedDic];
self.myTextField.attributedPlaceholder = placeholderAttributedString;

Status Bar 的样式更新

原来的StatusBar的样式一共有两种

1
2
UIStatusBarStyleDefault = 0, // Automatically chooses light or dark content based on the user interface style
UIStatusBarStyleLightContent API_AVAILABLE(ios(7.0)) = 1, // Light content, for use on dark backgrounds

其中

  • UIStatusBarStyleDefault 黑色文字
  • UIStatusBarStyleLightContent 白色文字

在iOS13中,StatusBar新增了一种样式

1
2
3
UIStatusBarStyleDefault = 0, // Automatically chooses light or dark content based on the user interface style
UIStatusBarStyleLightContent API_AVAILABLE(ios(7.0)) = 1, // Light content, for use on dark backgrounds
UIStatusBarStyleDarkContent API_AVAILABLE(ios(13.0)) = 3, // Dark content, for use on light backgrounds

其中

  • UIStatusBarStyleDefault 系统会自动选择黑色或者白色
  • UIStatusBarStyleDarkContent 黑色文字
  • UIStatusBarStyleLightContent 白色文字

Modal新样式

在iOS13中,所有的present效果都默认变成了小卡片的类型。苹果真是极大力的推广这个样式。
而且非常方便的一个地方是,可是直接下拉页面出发dismiss,对于用户体验提升非常大。
那看一下苹果为了这个新的Modal样式加了多少东西:

UIModalPresentationStyle

首先是对UIModalPresentationStyle新增了一个UIModalPresentationAutomatic属性。这个就是在iOS13情况下的默认属性。他会自动根据即将present的控制器来选择不同的style。比如我们自定义的控制器,那系统就会默认将他作为UIModalPresentationPageSheet来显示,而像系统的UIImagePickerController的话,就会使用UIModalPresentationFullScreen来显示。

1
2
3
4
5
6
/*
Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter.
If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but system-provided subclasses may resolve UIModalPresentationAutomatic to other concrete presentation styles. Participation in the resolution of UIModalPresentationAutomatic is reserved for system-provided view controllers.
Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms.
*/
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));
1
2
3
4
5
6
7
8
9
10
11
12
13
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,
};

那么这个新的属性会来带什么问题呢,最坑的就是对于控制器的生命周期来说有一个很大的影响。
先上两张图。

logo

logo

这两张图就可以很明显的看出两种style的区别。

举个🌰:
我在A控制器中present B控制器,这时候A的viewWillDisappearviewDidDisappear都不会调用;
同样的,当B控制器dismiss的时候,A的viewWillAppearviewDidAppear也都不会调用;

这个就真的很坑了

modalInPresentation

另外针对于present上来的控制器,可以通过手势下拉dismiss的功能。iOS13中提供了一个新的属性来控制。

1
2
// modalInPresentation is set on the view controller when you wish to force the presentation hosting the view controller into modal behavior. When this is active, the presentation will prevent interactive dismiss and ignore events outside of the presented view controller's bounds until this is set to NO.
@property (nonatomic, getter=isModalInPresentation) BOOL modalInPresentation API_AVAILABLE(ios(13.0));

这个属性默认的状态时false,这个情况下,用户是可以通过下拉手势dismiss控制器的,那当你想要阻止用户做这个操作的时候,比如当前页面中有输入的内容,你并不想让用户这么轻易的返回导致输入的内容丢失,就可以将这个属性设置为true。官方也出了一个Demo来展示如何使用这个。

通过Demo中的内容,我们可以看到UIAdaptivePresentationControllerDelegate代理中的presentationControllerDidAttemptToDismiss会在isModalInPresentation为true的情况下,并且用户准备下来返回时调用。

参考资料

https://juejin.im/post/5d00af64e51d455d88219ee2

https://github.com/ChenYilong/iOS13AdaptationTips/issues?q=is%3Aissue+is%3Aopen+label%3Anote

https://blog.csdn.net/qq_42792413/article/details/97392996

https://juejin.im/post/5cf946b3e51d45108b2cae3b