iOS高級分享 — 談談 IOS 13

爲了記念上週發佈的iOS13,咱們來看一看你如今能夠在你的應用程序中使用的一些模糊的(基本上是沒有文檔的)API。咱們已經清除了最好的部分IOS13發行說明API差別如今把它們呈現給你。 下面是咱們最喜歡的一些從iOS 13開始能夠作的事情:html

生成URL的富表示

新的IOS 13,連接呈現框架提供一種方便的內置方式來複制您在消息中看到的URL的豐富預覽。若是您的應用程序有任何聊天或消息功能,您確定會想要檢查這一點。ios

豐富的URL預覽至少能夠追溯到20世紀初,隨着微格式由語義web先驅和早期先驅使用khtml2png若要生成網頁的縮略圖圖像,請執行如下操做。快到2010年,隨着社交媒體和用戶生成的內容的興起,facebook建立了OpenGraphProtocol容許網絡出版商自定義其頁面的外觀時,張貼在新聞提要。git

現在,大多數網站都有開放圖形標籤在他們的網站上,爲社會網絡,搜索引擎,以及任何其餘連接被販運的地方提供他們的內容摘要。例如,若是您對這個網頁進行了「查看源」,您將看到如下內容:web

<meta property="og:site_name" content="NSHipster" />
<meta property="og:image" content="https://nshipster.com/logo.png" />
<meta property="og:type" content="article" />
<meta property="og:title" content="iOS 13" />
<meta property="og:url" content="https://nshipster.com/ios-13/" />
<meta property="og:description" content="To mark last week's release of iOS 13, we're taking a look at some obscure (largely undocumented) APIs that you can now use in your apps." />
複製代碼

若是您想在應用程序中使用這些信息,如今可使用LinkPresting框架的LPMetadataProvider類來獲取元數據,並可選擇地構造一個表示:api

import LinkPresentation

let metadataProvider = LPMetadataProvider()
let url = URL(string: "https://nshipster.com/ios-13/")!

let metadataProvider = LPMetadataProvider()
metadataProvider.startFetchingMetadata(for: url) { [weak self] metadata, error in
    guard let metadata = metadata else { return }

    let linkView = LPLinkView(metadata: metadata)
    self?.view.addSubview(linkView)
}
複製代碼

在設置適當的約束(或者調用sizeToFit()),您將獲得如下內容,用戶能夠點擊它預覽連接的網頁:bash

在startFetchingMetadata(for:)完成處理程序,您能夠檢查和變異從服務器檢索的元數據。您可能會利用這個機會爲沒有這些內容的頁面添加默認的圖像/視頻,將文本翻譯成用戶首選的語言之一,或者檢查顯式文本和媒體。服務器

或者,若是您已經在-app中擁有元數據,或者不能或不但願遠程獲取元數據,則能夠構造一個LPLinkMetadata直接:網絡

let metadata = LPLinkMetadata()
metadata.url = url
metadata.title = "iOS 13"
metadata.iconProvider = ...

let linkView = LPLinkView(metadata: metadata)
複製代碼

LPMetadataProvider在IOS上作廣告,但MacOS客戶端必須具備com.apple.security.network.client權限,以便從遠程URL獲取元數據。session

執行設備上語音識別

SFSpeechRecognizer在iOS 13中得到一次重大升級-最顯著的是它增長了對設備上語音識別的支持。app

之前,抄寫須要一個互聯網鏈接,而且被限制在最多1分鐘的時間內,天天的請求都有限制。可是如今,你能夠徹底在設備上和離線下進行語音識別,沒有任何限制.惟一要注意的是,離線轉錄不如服務器鏈接的效果好,並且只適用於某些語言。

若要肯定脫機轉錄是否可用於用戶的區域設置,請檢查SFSpeechRecognizer財產supportsOnDeviceRecognition..在出版時,所支持的語文清單以下:

根據IOS 13發佈說明:「supportsOnDeviceRecognition屬性老是返回false第一次被訪問的時候。幾秒鐘後,再次訪問它將返回正確的值。「

但這並非iOS 13中的所有語音識別!SFSpeechRecognizer如今提供信息,包括說話速率和平均停頓時間,以及語音分析功能,如抖動(音高的變化)和閃光器(振幅的變化)。

import Speech

guard SFSpeechRecognizer.authorizationStatus() == .authorized
    let recognizer = SFSpeechRecognizer()
else {
    fatalError()
}

let url: URL = ...
let request = SFSpeechURLRecognitionRequest(url: url)

recognizer.recognitionTask(with: request) { (result, error) in
    guard let result = result else { return }

    for segment in result.bestTranscription.segments {
        guard let voiceAnalytics = segment.voiceAnalytics else { continue }

        let pitch = voiceAnalytics.pitch.acousticFeatureValuePerFrame
        let voicing = voiceAnalytics.voicing.acousticFeatureValuePerFrame
        let jitter = voiceAnalytics.jitter.acousticFeatureValuePerFrame
        let shimmer = voiceAnalytics.shimmer.acousticFeatureValuePerFrame
    }
}
複製代碼

您的應用程序可使用有關音調、語音和其餘功能的信息(可能)。協同CoreML)區分說話人或從說話人的拐彎處肯定潛臺詞。

發送和接收Web套接字消息

說到FoundationURL加載系統,咱們如今已經有了本機支持的東西,這些東西在咱們的願望列表中佔據了不少年的首位:Web套接字.

多虧了新的URLSessionWebSocketTask在IOS 13中,您如今能夠像發送HTTP請求同樣輕鬆可靠地在應用程序中集成實時通訊-全部這些都沒有任何第三方庫或框架:

let url = URL(string: "wss://...")!
let webSocketTask = URLSession.shared.webSocketTask(with: url)
webSocketTask.resume()

// Configure how messages are received
webSocketTask.receive { result in
    guard let .success(message) = result else { return }
    ...
}

// Send a message
let message: URLSessionWebSocketTask.Message = .string("Hello, world!")
webSocketTask.send(message) { error in
    ...
}

// Eventually...
webSocketTask.cancel(with: .goingAway, reason: nil)
複製代碼

對於web套接字的低級控制,包括客戶端和服務器支持,請查看網絡框架.

多年來,網絡可能一直是整個蘋果技術體系中移動最快的部分。每一個WWDC,都有太多要談論的話題,以致於他們不得不在兩個不一樣的會議上打破他們的內容。2019年也不例外,咱們強烈建議你花點時間看看今年的「網絡進步」會議(第一部分, 第二部分).

用地圖作更多

MapKit是Apple SDK的另外一個組成部分,它在WWDC上年復一年地表現強勁。在咱們平常生活中,影響最大的每每是那些小小的觸碰。

例如,新的MKMapView.CameraBoundaryiOS 13中的API使得在不徹底鎖定地圖的狀況下將地圖的視口限制到特定區域變得容易得多。

let region = MKCoordinateRegion(center: mapView.center,
                                        latitudinalMeters: 1000,
                                        longitudinalMeters: 1000)
mapView.cameraBoundary = MKMapView.CameraBoundary(coordinateRegion: region)
複製代碼

新的MKPointOfInterestFilterapi,您如今能夠自定義地圖視圖的外觀,只顯示特定類型的興趣點。(而之前是全無命題).

let filter = MKPointOfInterestFilter(including: [.cafe])
mapView.pointOfInterestFilter = filter // only show cafés
複製代碼

最後,用MKGeoJSONDecoder,咱們如今有一個內置的方式來拉進來。GeoJSON來自Web服務和其餘數據源的形狀。

let decoder = MKGeoJSONDecoder()

if let url = URL(string: "..."),
    let data = try? Data(contentsOfURL: url),
    let geoJSONObjects = try? decoder.decode(data) {

    for case let overlay as MKOverlay in geoJSONObjects {
        mapView.addOverlay(overlay)
    }
}
複製代碼

用JavaScript信守諾言

若是你喜歡咱們的文章JavaScriptCore,你會很高興知道JSValue對象如今本地支持承諾.

對於不熟悉的人:在JavaScript中,Promise表示異步操做的最終完成(或拒絕)及其結果值的對象。承諾是現代JS開發的支柱-也許最值得注意的是fetchAPI

iOS 13中JavaScriptCore的另外一個補充是對符號(不,不是那些符號)。有關init(newSymbolFromDescription:in:), 參考文檔 猜猜怎麼用。

對目標C相關對象的響應(?)

在雲雀上,咱們決定看看目標C今年是否有什麼新發現,並驚訝地發現objc_setHook_setAssociatedObject..一樣,除了聲明以外,咱們沒有什麼可繼續進行的,可是如今您彷佛能夠配置一個塊,以便在關聯對象已經設定好了。對於任何仍深刻目標C運行時的人來講,這聽起來很方便。

馴服活動項目(?)

關於失蹤文件的問題:UIActivityItemsConfiguration彷佛就像在新的iOS13共享表中管理操做的一個頗有吸引力的選項,可是咱們不知道從哪裏開始…

遺憾的是,咱們尚未足夠的信息來利用這一點。

格式列表和相關時間

中討論過的前一篇文章,IOS 13爲基金會帶來了兩個新的格式:ListFormatter和RelativeDateTimeFormatter.

不是爲了嘮叨這件事,但他們都是仍然所以,若是您想了解更多信息,咱們建議您從7月份開始查看這篇文章。或者,若是您很着急,下面是一個演示如何將二者結合使用的快速示例:

import Foundation

let relativeDateTimeFormatter = RelativeDateTimeFormatter()
relativeDateTimeFormatter.dateTimeStyle = .named

let listFormatter = ListFormatter()
listFormatter.string(from: [
    relativeDateTimeFormatter.localizedString(from: DateComponents(day: -1)),
    relativeDateTimeFormatter.localizedString(from: DateComponents(day: 0)),
    relativeDateTimeFormatter.localizedString(from: DateComponents(day: 1))
]) // "yesterday, today, and tomorrow"
複製代碼

跟蹤排隊操做的進展

從iOS 13開始,OperationQueue如今有一個progress財產。

固然,(NS)Progress對象並非最簡單、最方便的東西(咱們一直打算在某個時候寫一篇關於它們的文章),可是它們有一個完整的、通過深思熟慮的API,甚至在應用程序框架中也有一些方便的插槽。

例如,檢查鏈接一個UIProgressView若要以其方式顯示操做隊列的實時更新進度,請執行如下操做:observedProgress財產:

import UIKit

fileprivate class DownloadOperation: Operation { ... }

class ViewController: UIViewController {
    private let operationQueue = {
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
    }()

    @IBOutlet private var progressView: UIProgressView!

    @IBAction private func startDownloading(_ sender: Any) {
        operationQueue.cancelAllOperations()
        progressView.observedProgress = operationQueue.progress

        for url in [...] {
            let operation = DownloadOperation(url: url)
            operationQueue.addOperation(operation)
        }
    }
}
複製代碼

還值得一提的是13歲時出現的其餘一些API,如schedule(after:interval:tolerance:options::),哪條線索OperationQueue進入新的組合框架以一種很好的方式,並且addBarrierBlock(:),它的工做原理多是調度屏障(雖然沒有文檔,但這是任何人的猜想)。

輕鬆管理後臺任務

定義應用程序與競爭對手的區別之一是,它們使用後臺任務來確保應用程序在下一次進入前臺時獲得充分同步和更新。

iOS 7是第一個提供用於調度後臺任務的官方API (儘管在此以前,開發人員使用了各類創造性的方法)..但在這段時間裏,多個因素-從iOS應用程序能力和複雜性的提升,到對應用程序的性能、效率和隱私的日益重視-催生了對更全面解決方案的需求。

該解決方案是經過新的iOS 13實現的。背景測試框架.

現在年WWDC會議所述「應用程序後臺執行的進展」該框架區分了兩大類背景任務:

  • 應用程序刷新任務:短命的任務,使應用程序一成天都保持最新。
  • 背景處理任務*用於執行可推遲的維護任務的長期任務

WWDC會話和附帶的示例代碼項目很好地解釋瞭如何將這二者結合到您的應用程序中。可是,若是您想要它的快速要點,下面是一個應用程序從Web服務器按期刷新的一個小例子:

import UIKit
import BackgroundTasks

fileprivate let backgroundTaskIdentifier = "com.nshipster.example.task.refresh"

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    lazy var backgroundURLSession = {
        let configuration = URLSessionConfiguration.background(withIdentifier: "com.nshipster.url-session.background")
        configuration.discretionary = true
        configuration.timeoutIntervalForRequest = 30

        return URLSession(configuration: configuration, delegate: ..., delegateQueue: ...)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       ...

        BGTaskScheduler.shared.register(forTaskWithIdentifier: backgroundTaskIdentifier, using: nil) { task in
            self.handleAppRefresh(task: task as! BGAppRefreshTask)
        }

        return true
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        scheduleAppRefresh()
    }

    func scheduleAppRefresh() {
        let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)
        request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 10)

        do {
            try BGTaskScheduler.shared.submit(request)
        } catch {
            print("Couldn't schedule app refresh: \(error)")
        }
    }

    func handleAppRefresh(task: BGAppRefreshTask) {
        scheduleAppRefresh()

        let url: URL = ...
        var dataTask = backgroundURLSession.dataTask(with: url) { (data, response, error) in
            ...
            let success = (200..<300).contains(response?.statusCode)
            task.setTaskCompleted(success: success)
        }

        task.expirationHandler = {
            dataTask.cancel()
        }

        dataTask.resume()
    }

    ...
}
複製代碼

之前進行背景更新的方法-即,UIApplication.setMinimumBackgroundFetchInterval(:)和UIApplicationDelegate.application(:performFetchWithCompletionHandler:)-如今已在IOS 13中被否決。

註釋文本內容類型以得到更好的可訪問性。 你知道聽到一些人讀出網址是多麼使人沮喪嗎?「eɪʧtipiˈkoʊlənslʃˈdʌbəljuˈdʌbəljudɑt」…)這就是當畫外音試圖在不瞭解更多信息的狀況下閱讀一些東西什麼在看書。

iOS 13承諾經過新的accessibilityTextualContext財產和UIAccessibilityTextAttributeContextNSAttributedString屬性鍵只要有可能,必定要用最能描述所顯示的文本類型的常量對視圖和屬性字符串進行註釋:

  • UIAccessibilityTextualContextConsole
  • UIAccessibilityTextualContextFileSystem
  • UIAccessibilityTextualContextMessaging
  • UIAccessibilityTextualContextNarrative
  • UIAccessibilityTextualContextSourceCode
  • UIAccessibilityTextualContextSpreadsheet
  • UIAccessibilityTextualContextWordProcessing

隱式刪除從情節提要初始化的視圖控制器中的未包裝選項

SwiftUI可能已經預示了故事板的最終結束,但這並不意味着事情不是也不會繼續好轉,直到那一天到來。

對於斯威夫特純粹主義者來講,在使用故事板進行iOS項目時,最使人惱火的反模式之一就是視圖控制器初始化。因爲Interface Builder的「準備」方法與SWIFT的對象初始化規則之間的阻抗不匹配,咱們常常不得不在使全部屬性成爲非私有、變量和(隱式展開)選項之間進行選擇,或者徹底選擇前面的故事板。

Xcode 11和IOS 13容許這些範例經過新的方式來協調它們之間的差別。@IBSegueAction屬性和一些新的UIStoryboard班級方法:

首先,@IBSegueAction屬性能夠應用視圖控制器方法聲明來指定本身爲API,負責建立segue的目標視圖控制器。(即destinationViewController的屬性segue參數中的prepare(for:sender:)方法).

@IBSegueAction
func makeProfileViewController(coder: NSCoder, sender: Any?, segueIdentifier: String?) -> ProfileViewController? {
    ProfileViewController(
        coder: coder,
        name: self.selectedName,
        avatarImageURL: self.selectedAvatarImageURL
    )
}
複製代碼

第二,UIStoryboard類方法instantiateInitialViewController(creator:)和instantiateViewController(identifier:creator:)提供一個方便的基於塊的定製點來實例化Storyboard的視圖控制器.

import UIKit

struct Person { ... }

class ProfileViewController: UIViewController {
    let name: String
    let avatarImageURL: URL?

    init?(coder: NSCoder, name: String, avatarImageURL: URL?) {
        self.name = name
        self.avatarImageURL = avatarImageURL

        super.init(coder: coder)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

let storyboard = UIStoryboard(name: "ProfileViewController", bundle: nil)
storyboard.instantiateInitialViewController(creator: { decoder in
    ProfileViewController(
        coder: decoder,
        name: "Johnny Appleseed",
        avatarImageURL: nil
    )
})
複製代碼

和新的UIKit場景在咱們等待SwiftUI成熟和穩定的時候,iOS 13提供了大量的工做。

這是爲了咱們的iOS 13功能的總結性,你可能已經錯過了。可是請放心-咱們計劃在將來的NSHipster文章中涵蓋更多的新API。

若是遺漏了什麼你想讓咱們來掩護,請經過加咱們的交流羣 點擊此處進交流羣 ,來一塊兒交流或者發佈您的問題,意見或反饋。

原文地址 nshipster.com/ios-13/#tra…

相關文章
相關標籤/搜索