2016-09-21 59 views
72

考虑:斯威夫特3可选逃避关闭参数

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),并保持@escaping

更改类型提供了以下错误:

error: @escaping attribute only applies to function types

卸下@escaping属性,代码编译和运行,但似乎并没有被正确的,因为completion关闭是逃逸的范围功能。

+10

“卸下'@ escaping'属性,代码编译并运行“ - 这是因为,正如[SR-2444](https://bugs.swift.org/browse/SR-2444)中所述,”Action?“默认情况下是转义的。所以,使用可选闭包时删除'@ escaping'就能完成你所需要的。 – Rob

+0

相关:[更新闭包到Swift 3 - @escaping](http://stackoverflow.com/questions/39063499/updating-closures-to-swift-3-escaping/)。 – dfri

+0

类型别名关闭正在转义 – Masih

回答

59

有一个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() 

编辑:

我其实下的Xcode 8 beta版,其中的bug SR-2552尚未解决。修复这个错误,引入一个新的(你面临的)仍然是开放的。请参阅SR-2444

解决方法迈克尔Ilseman指出作为临时解决方案是移除可选功能类型@escaping属性,即保持功能逸出。

func doStuff(stuff: String, completion: Action?) {...} 
+3

现在让'@escaping可能只适用于函数类型的参数 func doStuff(stuff:String,completion:(@escaping() - >())?){' –

+0

Right,please see编辑。 – xhamr

+1

'临时解决方案是从可选的函数类型中删除@escaping属性,使函数保持转义状态。“你能解释一下吗? swift 3中的默认语义是非转义的。虽然它没有@escaping进行编译,但恐怕它会被视为无法转义而导致问题。这不正确吗? –

92

来自:swift-users mailing list

Basically, @escaping is valid only on closures in function parameter position. The noescape-by-default rule only applies to these closures at function parameter position, otherwise they are escaping. Aggregates, such as enums with associated values (e.g. Optional), tuples, structs, etc., if they have closures, follow the default rules for closures that are not at function parameter position, i.e. they are escaping.

所以可选功能参数默认@escaping。
@noeascape默认只适用于函数参数。

+2

我认为这增加了最重要的信息给主题,它应该被接受的答案。 –

+0

合理的答案。这可能会改变的可能性有多大? – GoldenJoe

+0

这是有道理的,因为从技术上说'(( - ) - > Void)?'是说你有'可选<()-> Void>'并且为了让'Optional'保持所有权,它必须只接受'@escaping '功能。 我会第三,这应该是被接受的答案。谢谢。 –

9

我遇到类似的问题,因为混合@escaping和非@escaping是非常混乱,尤其是如果你需要通过关闭周围。我结束了默认参数(我认为更有意义)

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) 
} 
+0

这是干净漂亮的实施。 –

+1

如果我想检查这个块是否为空,该怎么办? –

+0

无赖,这不适用于协议方法。 “在协议方法中不允许的默认参数”(Xcode 8.3.2)。 –

6

我得到了它在斯威夫特3个工作没有任何警告仅是这样的:

func doStuff(stuff: String, completion: (()->())?) { 
    print(stuff) 
    action = completion 
    completion?() 
}