[英]Swift optional escaping closure parameter
鑒於:
typealias Action = () -> ()
var action: Action = { }
func doStuff(stuff: String, completion: @escaping Action) {
print(stuff)
action = completion
completion()
}
func doStuffAgain() {
print("again")
action()
}
doStuff(stuff: "do stuff") {
print("swift 3!")
}
doStuffAgain()
有什么方法可以制作Action?
類型的completion
參數(和action
) Action?
並保持@escaping
?
更改類型會出現以下錯誤:
@escaping 屬性僅適用於函數類型
刪除@escaping
屬性,代碼編譯並運行,但似乎不正確,因為completion
閉包正在轉義函數的范圍。
來自: swift-users 郵件列表
基本上,@escaping 僅對函數參數位置的閉包有效。 noescape-by-default 規則僅適用於函數參數位置的這些閉包,否則它們將被轉義。 聚合體,例如帶有關聯值的枚舉(例如 Optional)、元組、結構體等,如果它們有閉包,那么對於不在函數參數位置的閉包,即它們是轉義的,遵循默認規則。
所以可選的函數參數默認是@escaping。
@noeascape 默認僅適用於函數參數。
有一個SR-2552報告說@escaping
無法識別函數類型別名。 這就是錯誤@escaping attribute only applies to function types
。 您可以通過擴展函數簽名中的函數類型來解決:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: (@escaping ()->())?) {
print(stuff)
action = completion
completion?()
}
func doStuffAgain() {
print("again")
action?()
}
doStuff(stuff: "do stuff") {
print("swift 3!")
}
doStuffAgain()
編輯 1: :
我實際上是在 xcode 8 beta 版本下,其中錯誤SR-2552尚未解決。 修復該錯誤,引入了一個仍處於打開狀態的新錯誤(您面臨的錯誤)。 見SR-2444 。
@Michael Ilseman指出的臨時解決方法是從可選函數類型中刪除@escaping
屬性,使函數保持為 escaping 。
func doStuff(stuff: String, completion: Action?) {...}
編輯2 ::
該SR-2444已經被關閉,說明明確,在參數關閉位置不逃逸,需要他們被打上@escaping
讓他們逃脫,但可選參數隱含逃脫,因為((Int)->())?
是Optional<(Int)->()>
的同義詞,可選閉包正在轉義。
我遇到了類似的問題,因為混合@escaping
和非@escaping
非常令人困惑,特別是如果您需要傳遞閉包。
我最終通過= { _ in }
為閉包參數分配了一個無操作默認值,我認為這更有意義:
func doStuff(stuff: String = "do stuff",
completion: @escaping (_ some: String) -> Void = { _ in }) {
completion(stuff)
}
doStuff(stuff: "bla") {
stuff in
print(stuff)
}
doStuff() {
stuff in
print(stuff)
}
我讓它在 Swift 3 中工作,沒有任何警告,只有這樣:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
在示例中要理解的重要一點是,如果將Action
更改為Action?
關閉正在逃脫。 所以,讓我們按照你的建議去做:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
好的,現在我們將調用doStuff
:
class ViewController: UIViewController {
var prop = ""
override func viewDidLoad() {
super.viewDidLoad()
doStuff(stuff: "do stuff") {
print("swift 3!")
print(prop) // error: Reference to property 'prop' in closure
// requires explicit 'self.' to make capture semantics explicit
}
}
}
嗯,這個要求只出現在轉義閉包中。 所以關閉正在逃逸。 這就是為什么你沒有將它標記為轉義 - 它已經在轉義了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.