Luk*_*asz 108 closures swift swift3 xcode8-beta6
我有一个协议:
enum DataFetchResult {
case success(data: Data)
case failure
}
protocol DataServiceType {
func fetchData(location: String, completion: (DataFetchResult) -> (Void))
func cachedData(location: String) -> Data?
}
Run Code Online (Sandbox Code Playgroud)
通过示例实现:
/// An implementation of DataServiceType protocol returning predefined results using arbitrary queue for asynchronyous mechanisms.
/// Dedicated to be used in various tests (Unit Tests).
class DataMockService: DataServiceType {
var result : DataFetchResult
var async : Bool = true
var queue : DispatchQueue = DispatchQueue.global(qos: .background)
var cachedData : Data? = nil
init(result : DataFetchResult) {
self.result = result
}
func cachedData(location: String) -> Data? {
switch self.result {
case .success(let data):
return data
default:
return nil
}
}
func fetchData(location: String, completion: (DataFetchResult) -> (Void)) {
// Returning result on arbitrary queue should be tested,
// so we can check if client can work with any (even worse) implementation:
if async == true {
queue.async { [weak self ] in
guard let weakSelf = self else { return }
// This line produces compiler error:
// "Closure use of non-escaping parameter 'completion' may allow it to escape"
completion(weakSelf.result)
}
} else {
completion(self.result)
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在Swift3(Xcode8-beta5)中编译和工作,但不再适用于beta 6.你能指出我的根本原因吗?
Ham*_*ish 191
这是由于函数参数的默认行为发生了变化.在Swift 3之前(特别是随Xcode 8 beta 6一起提供的版本),它们将默认为转义 - 您必须将它们标记为@noescape防止它们被存储或捕获,因此保证它们不会被调用功能退出.
但是,现在@noescape是默认值 - 您现在必须标记函数参数,@escaping以告诉编译器可以存储或捕获它们.
protocol DataServiceType {
func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)
func cachedData(location: String) -> Data?
}Run Code Online (Sandbox Code Playgroud)
func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void) {
// ...
}Run Code Online (Sandbox Code Playgroud)
有关此更改的详细信息,请参阅Swift Evolution提案.
Vit*_*lii 16
由于@noescape是默认值,因此有2个选项可以修复错误:
1)正如@Hamish在他的回答中指出的那样,如果你关心结果并且真的希望它能够逃脱,那么只需将完成标记为@escaping(这可能是@Lukasz的问题,单元测试作为示例和异步的可能性完成)
func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)
Run Code Online (Sandbox Code Playgroud)
要么
2)保留默认的@noescape行为,使得完成可选,在您不关心结果的情况下完全丢弃结果.例如,当用户已经"离开"并且呼叫视图控制器不必因为有一些粗心的网络呼叫而挂在内存中.正如在我的情况下,当我来到这里寻找答案时,示例代码对我来说并不是很相关,所以标记@noescape并不是最好的选择,尽管它从第一眼开始就是唯一的一个.
func fetchData(location: String, completion: ((DataFetchResult) -> Void)?) {
...
completion?(self.result)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
49244 次 |
| 最近记录: |