1. 暗黑模式Dark Mode
如果不打算適配 Dark Mode角钩,可以直接在
Info.plist
中添加一欄:User Interface Style : Light
吝沫,即可在應(yīng)用內(nèi)禁用暗黑模式不過即使設(shè)置了顏色方案,申請權(quán)限的系統(tǒng)彈窗還是會依據(jù)系統(tǒng)的顏色進行顯示,自己創(chuàng)建的 UIAlertController 就不會
2. 第三方快捷登錄Sign In with Apple
蘋果在 App Store 應(yīng)用審核指南 中提到:
如果你的應(yīng)用使用了第三方或社交賬號登錄服務(wù)(如Facebook、Google搞糕、Twitter、LinkedIn辫愉、Amazon、微信等)來設(shè)置或驗證用戶的主賬號将硝,就必須把 Sign In With Apple 作為同等的選項添加到應(yīng)用上恭朗。
3. 私有方法 KVC 可能導(dǎo)致崩潰
并不是所有kvc都會崩潰,但是有很多以前可修改的屬性都不行了袋哼,只能靠試
// 崩潰 api冀墨。獲取 _placeholderLabel 不會崩潰,但是獲取 _placeholderLabel 里的屬性就會
[textField setValue:[UIColor blueColor] forKeyPath:@"_placeholderLabel.textColor"];
[textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"_placeholderLabel.font"];
// 替代方案 1涛贯,去掉下劃線诽嘉,訪問 placeholderLabel
[textField setValue:[UIColor blueColor] forKeyPath:@"placeholderLabel.textColor"];
[textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"placeholderLabel.font"];
// 替代方案 2
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"輸入" attributes:@{
NSForegroundColorAttributeName: [UIColor blueColor],
NSFontAttributeName: [UIFont systemFontOfSize:20]
}];
4. 通知deviceToken格式變化
iOS13之前獲取token方式
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [deviceToken description];
for (NSString *symbol in @[@" ", @"<", @">", @"-"]) {
token = [token stringByReplacingOccurrencesOfString:symbol withString:@""];
}
NSLog(@"deviceToken:%@", token);
}
iOS13起獲取token方式
{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:@"xxxxxxxx",
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);
}
5. 模態(tài)彈窗樣式
蘋果將 UIViewController 的 modalPresentationStyle 屬性的默認(rèn)值改成了新加的一個枚舉值 UIModalPresentationAutomatic,對于多數(shù) UIViewController,此值會映射成 UIModalPresentationPageSheet虫腋,而以前我們都是用全屏fullScreen的樣式
特別注意:非全屏情況下骄酗,將這個頁面彈出的那個 ViewController
不會依次調(diào)用
viewWillDisappear 和 viewDidDisappear。然后在這個頁面被 dismiss 的時候悦冀,將他彈出的那個 ViewController不會依次調(diào)用
viewWillAppear 和 viewDidAppear
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let dest = HomeVC()
// 修改彈出樣式
dest.modalPresentationStyle = .fullScreen
present(dest, animated: true, completion: nil)
}
6. 導(dǎo)航欄左右按鈕邊距
從 iOS 11 開始趋翻,UINavigationBar 使用了自動布局,左右兩邊的按鈕到屏幕之間會有 16 或 20 的邊距盒蟆。
為了避免點擊到間距的空白處沒有響應(yīng)踏烙,通常做法是:定義一個 UINavigationBar 子類,重寫 layoutSubviews 方法历等,在此方法里遍歷 subviews 獲取 _UINavigationBarContentView讨惩,并將其 layoutMargins 設(shè)置為 UIEdgeInsetsZeroiOS 13:此方式會crash,使用設(shè)置 frame 的方式寒屯,讓 _UINavigationBarContentView 向兩邊伸展荐捻,從而抵消兩邊的邊距
import UIKit
class SMNavigationBar: UINavigationBar {
override func layoutSubviews() {
super.layoutSubviews()
for subview in subviews {
if NSStringFromClass(subview.classForCoder).contains("_UINavigationBarContentView") {
if (UIDevice.current.systemVersion as NSString).doubleValue >= 13.0 {
let margins = subview.layoutMargins
subview.frame = CGRect(x: -margins.left + 10, y: -margins.top, width: margins.left + margins.right + subview.frame.size.width, height: margins.top + margins.bottom + subview.frame.size.height)
}else {
subview.layoutMargins = UIEdgeInsets.zero
}
}
}
}
}
7. LaunchImage 被棄用
是時候跟LaunchImage告別了, iOS 8 蘋果引入了 LaunchScreen寡夹,從2020年4月開始处面,所有支持 iOS 13 的 App 必須提供 LaunchScreen.storyboard,否則將無法提交到 App Store 進行審批
8. UISegmentedControl 默認(rèn)樣式改變
默認(rèn)樣式變?yōu)榘椎缀谧制刑停兊糜悬c擬物化的感覺魂角,原本設(shè)置選中顏色的 tintColor 已經(jīng)失效,新增了 selectedSegmentTintColor 屬性用以修改選中的顏色
注意:通過selectedSegmentTintColor很難精準(zhǔn)跳轉(zhuǎn)顏色患蹂,比如設(shè)置背景色為白色或颊,是無效的(它會自動調(diào)整一下顏色對比),這個時候要通過背景圖片來設(shè)置
假設(shè)做一個選中紅底白字传于,未選中白底紅字的分段控制器
/// 定制分段控制器樣式
private func customStyle() {
if #available(iOS 13.0, *) {
control.setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.red], for: UIControl.State.normal)
control.setBackgroundImage(imageFromColor(color: UIColor.white), for: UIControl.State.normal, barMetrics: .default)
control.setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.white], for: UIControl.State.selected)
control.setBackgroundImage(imageFromColor(color: UIColor.red), for: UIControl.State.selected, barMetrics: .default)
control.layer.borderColor = UIColor.red.cgColor
control.layer.borderWidth = 1.0
} else {
control.backgroundColor = .white
control.tintColor = .red
}
}
/// 把顏色轉(zhuǎn)成圖片
private func imageFromColor(color: UIColor) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(rect)
let theImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return theImage
}
9. UIWindow視圖管理UIScene
使用 Xcode 11 創(chuàng)建的工程,運行設(shè)備選擇 iOS 13.0 以下的設(shè)備醉顽,運行應(yīng)用時會出現(xiàn)黑屏沼溜。這是因為 Xcode 11 默認(rèn)是會創(chuàng)建通過 UIScene 管理多個 UIWindow 的應(yīng)用,工程中除了 AppDelegate 外會多一個 SceneDelegate游添;這是為了 iPadOS 的多進程準(zhǔn)備的系草,也就是說 UIWindow 不再是 UIApplication 中管理,但是舊版本根本沒有 UIScene
不搞iPad的話唆涝,如下處理:
- 刪除SceneDelegate文件
- info.plist中刪除
Application Scene Manifest
字段 - 在AppDelegate中添加window屬性
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
/// 加上window屬性
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
}