當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


Swift withoutActuallyEscaping(_:do:)用法及代碼示例

函數

withoutActuallyEscaping(_:do:)

允許臨時使用非轉義閉包,就好像它被允許逃逸一樣。

聲明

func withoutActuallyEscaping<ClosureType, ResultType>(
    _ closure: ClosureType,
    do body: (ClosureType) throws -> ResultType
) rethrows -> ResultType

返回值

body 閉包的返回值(如果有)。

參數

closure

body 閉包執行期間可轉義的非轉義閉包值。如果body 有返回值,則該值也用作withoutActuallyEscaping(_:do:) 函數的返回值。

body

使用 closure 的可逃避副本作為其參數立即執行的閉包。

詳述

您可以使用此函數調用一個 API,該 API 以一種不允許閉包在實踐中轉義的方式采用轉義閉包。下麵的示例演示了如何將 withoutActuallyEscaping(_:do:) 與使用轉義閉包的兩個常見 API 結合使用:惰性集合視圖和異步操作。

以下代碼聲明了一個 allValues(in:match:) 函數,用於檢查數組中的所有元素是否與謂詞匹配。該函數不會像編寫的那樣編譯,因為惰性集合的 filter(_:) 方法需要轉義閉包。惰性集合不會持久化,因此 predicate 閉包實際上不會轉義函數體;但是,它不能以這種方式使用。


func allValues(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
    return array.lazy.filter { !predicate($0) }.isEmpty
}
// error: closure use of non-escaping parameter 'predicate'...

withoutActuallyEscaping(_:do:) 提供了 predicate 的臨時可逃逸副本,can 可用於調用惰性視圖的 filter(_:) 方法。 allValues(in:match:) 的第二個版本編譯沒有錯誤,編譯器保證 escapablePredicate 閉包不會持續超過對 withoutActuallyEscaping(_:do:) 的調用。


func allValues(in array: [Int], match predicate: (Int) -> Bool) -> Bool {
    return withoutActuallyEscaping(predicate) { escapablePredicate in
        array.lazy.filter { !escapablePredicate($0) }.isEmpty
    }
}

異步調用是另一種類型的 API,通常會轉義其閉包參數。以下代碼聲明了一個perform(_:simultaneouslyWith:) 函數,該函數使用調度隊列同時執行兩個閉包。


func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void) {
    let queue = DispatchQueue(label: "perform", attributes: .concurrent)
    queue.async(execute: f)
    queue.async(execute: g)
    queue.sync(flags: .barrier) {}
}
// error: passing non-escaping parameter 'f'...
// error: passing non-escaping parameter 'g'...

perform(_:simultaneouslyWith:) 函數以使用.barrier 標誌調用sync(flags:execute:) 方法結束,這會強製函數等到兩個閉包都完成運行後再返回。盡管屏障保證兩個閉包都不會逃逸函數,但 async(execute:) 方法仍然要求傳遞的閉包標記為 @escaping ,因此函數的第一個版本無法編譯。要解決這些錯誤,您可以使用 withoutActuallyEscaping(_:do:) 獲取可以傳遞給 async(execute:)fg 的副本。


func perform(_ f: () -> Void, simultaneouslyWith g: () -> Void) {
    withoutActuallyEscaping(f) { escapableF in
        withoutActuallyEscaping(g) { escapableG in
            let queue = DispatchQueue(label: "perform", attributes: .concurrent)
            queue.async(execute: escapableF)
            queue.async(execute: escapableG)
            queue.sync(flags: .barrier) {}
        }
    }
}

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相關用法


注:本文由純淨天空篩選整理自apple.com大神的英文原創作品 withoutActuallyEscaping(_:do:)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。