iOS項目適配iOS13(Xcode11)

工程在Xcode11上編譯失敗的一些報錯,自行修改即可,大部分情況應該是代碼不夠規范導致的。至于這里,則主要總結下工程在Xcode11上正常編譯后,在iOS13系統手機上的一些問題。

問題一:

使用UITextField時,它的私有屬性_placeholderLabel被禁止訪問了

[_textField setValue:[UIFont boldSystemFontOfSize:14] forKeyPath:@"_placeholderLabel.font"];

在Xcode11上運行上述代碼會崩潰,崩潰信息如下:

reason: 'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug'

iOS 13 通過 KVC 方式修改私有屬性,有 Crash 風險,需謹慎使用!并不是所有KVC都會Crash,要嘗試!

刪除上述方法中@"_placeholderLabel.font"里的“_”,程序可以正常工作,但是不建議這樣做。

解決措施1,通過以下方法實現對placeholder屬性的設置:

_textField.attributedPlaceholder = [[NSAttributedString alloc]initWithString:NSLocalizedString(@"請輸入關鍵字", nil) attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:14], NSForegroundColorAttributeName:HexString(@"#A6A6A6")}];

解決措施2,需要添加頭文件#import <objc/runtime.h>

Ivar ivar = class_getInstanceVariable([UITextField class], "_placeholderLabel");

UILabel*placeholderLabel =object_getIvar(_textField, ivar);

placeholderLabel.textColor= [UIColorredColor];

問題二:

通過presentViewController彈出的模態控制器,彈出方式及效果和iOS13以前不同,這是因為UIViewController里的一個屬性modalPresentationStyle的默認值發生了改變。在iOS13之前,這個屬性的默認值是UIModalPresentationFullScreen,而在iOS13之后,默認值變成了UIModalPresentationAutomatic。和Xcode無關,只和iOS系統有關。

當然,嚴格意義上來說,這也不能算是一個問題,如果不能接受新的彈出效果,則只需要將控制器的modalPresentationStyle屬性設置下即可。為避免一處處去修改,我們可以通過UIViewController分類、重寫presentViewController等方式去實現。

問題三:

MPMoviePlayerController已經被棄用,在Xcode11上會Crash,信息如下:

reason: 'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'

解決措施:需要使用AVKit框架里的AVPlayerViewController來替代

問題四:

LaunchImage即將廢棄,得使用LaunchScreen來進行替換

從 iOS 8 的時候,蘋果就引入了 LaunchScreen,我們可以設置 LaunchScreen來作為啟動頁。當然,現在你還可以使用LaunchImage來設置啟動圖。不過使用LaunchImage的話,要求我們必須提供各種屏幕尺寸的啟動圖,來適配各種設備,隨著蘋果設備尺寸越來越多,這種方式顯然不夠 Flexible。而使用 LaunchScreen的話,情況會變的很簡單, LaunchScreen是支持AutoLayout+SizeClass的,所以適配各種屏幕都不在話下。

注意啦?,從2020年4月開始,所有使? iOS13 SDK的 App將必須提供 LaunchScreen,LaunchImage即將退出歷史舞臺

同時我們也可以看到,在Xcode11上,已經沒有了LaunchImage的選項:

圖1

如何使用LaunchScreen適配各種機型的手機?

如果單純使用一張啟動圖,是無法適配各種機型的,因為同一張圖在不同機型上可能會被拉伸變形。

因此,我們可以把一張啟動圖拆分開,拆成單獨的元素,在storyboard進行自動布局,這樣的話,就可以適配不同的機型、橫豎屏等情況了。

關于啟動頁實現、布局等內容具體可以參考一下鏈接:

啟動頁黑屏或白屏:http://www.lxweimin.com/p/d2b0f20e2e96

啟動頁強制豎屏,啟動后可以橫豎屏:https://www.coder4.com/archives/5406

使用Storyboard按比例自動布局技巧:https://blog.csdn.net/ws1352864983/article/details/52441938

問題五:

UIWindow,視圖層級發生了變化,如下圖,分別是Xcode11和Xcode11以前的版本下,UIWindow的視圖層級。

Xcode11
Xcode11以前

從上圖中,我們可以看到,UIWindow下的第一個子視圖不再是UILayoutContainerView,而是多出了UITransitionView、UIDropShadowView。

因此如果在iOS13上,我們如果想通過一下代碼獲取第一響應者,是獲取不到的

frontView = [[window subviews] objectAtIndex:0];

nextResponder = [frontView nextResponder];//iOS13上,獲取到的還是UIWindow(UITransitionView)

那么,如果我們在Xcode11下,還想要獲取到UILayoutContainerView怎么辦呢?可以通過類似下面的方式獲取到

? ? ? ? ? ? do {

? ? ? ? ? ? ? ? frontView = [[frontView subviews] objectAtIndex:0];

? ? ? ? ? ? } while ([frontView isKindOfClass:[UIView class]] && ![[frontView nextResponder] isKindOfClass:[UIViewController class]]);

問題六:

[[UIApplication sharedApplication] keyWindow] 方法即將被廢棄,被標記為API_DEPRECATED

我們可以看下官方描述:

@property(nullable, nonatomic,readonly) UIWindow *keyWindow API_DEPRECATED("Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes", ios(2.0, 13.0));

官方描述的意思是,不應用于在返回時支持多個場景的應用程序。而如果我們的程序只支持單一場景的話,

我們可以在Xcode11上分別獲取keywindow、windows里的subwindow來打印看看

test window ++++ keywindow :<UIWindow: 0x109600ec0; frame = (0 0; 834 1194); autoresize = W+H; gestureRecognizers = <NSArray: 0x283793f90>; layer = <UIWindowLayer: 0x2839ca8a0>>

test window --- subwindow :<UIWindow: 0x109600ec0; frame = (0 0; 834 1194); autoresize = W+H; gestureRecognizers = <NSArray: 0x283793f90>; layer = <UIWindowLayer: 0x2839ca8a0>>

test window --- subwindow :<UITextEffectsWindow: 0x10964b680; frame = (0 0; 834 1194); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x28399a620>>

可以得出結論,對于這種只支持單一場景的應用來說,可以使用[[[UIApplication sharedApplication] windows] objectAtIndex:0]來替換keywindow的方法。

tips:至于UITextEffectsWindow是什么東西,可以看這個

問題七:

WKWebView?中測量頁面內容高度的方式變更如下

iOS 13以前 document.body.scrollHeight?

iOS 13中 document.documentElement.scrollHeight 兩者相差55 應該是瀏覽器定義高度變了


問題八:

暗黑模式,若當前需要屏蔽暗黑模式,則需要在plist文件中增加一下配置項即可:

<key>UIUserInterfaceStyle</key>

<string>Light</string>

問題九:

presentViewController子線程執行時,會引發Crash,必須在主線程執行。

通常來說,大家都知道,UI操作必須放到主線程中執行,但是,在Xcode11以前,我們在使用presentViewController時,在子線程也可以正常使用,我們在器block中打印,發現已經回到了主線程。可以猜測,如果在子線程中使用presentViewController,系統會強制將其拉回到主線程中執行,所以不會引發異常。

但是,使用Xcode11后,在子線程使用presentViewController,會直接引發Crash,

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'threading violation: expected the main thread'

所以,切記,一切的UI操作都要放到主線執行。


參考鏈接:

https://www.jb51.net/article/169852.htm

http://www.lxweimin.com/p/a93a6f18b6c4

http://www.lxweimin.com/p/2ac8dbdcc88f/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。