SWIFT 3.0错误:"Escaping closures can only capture inout parameters explicitly by value",怎么解决?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (624)

我正试图将我的项目更新为SWIFT 3.0,但我遇到了一些困难。我得到了下一个错误:"Escaping closures can only capture inout parameters explicitly by value"。

问题在于这个函数内部:

fileprivate func collectAllAvailable(_ storage: inout [T], nextUrl: String, completion: @escaping CollectAllAvailableCompletion) {
    if let client = self.client {
        let _ : T? = client.collectionItems(nextUrl) {

            (resultCollection, error) -> Void in

            guard error == nil else {
                completion(nil, error)
                return
            }

            guard let resultCollection = resultCollection, let results = resultCollection.results else {
                completion(nil, NSError.unhandledError(ResultCollection.self))
                return
            }

            storage += results // Error: Escaping closures can only capture inout parameters explicitly by value

            if let nextUrlItr = resultCollection.links?.url(self.nextResourse) {

                self.collectAllAvailable(&storage, nextUrl: nextUrlItr, completion: completion) 
                // Error: Escaping closures can only capture inout parameters explicitly by value

            } else {
                completion(storage, nil) 
                // Error: Escaping closures can only capture inout parameters explicitly by value
            }
        }
    } else {
        completion(nil, NSError.unhandledError(ResultCollection.self))
    }
}

有人能帮我解决这个问题吗?

提问于
用户回答回答于

使用inout参数只适用于异步任务的inout-与调用函数时一样,调用方的值被传递到inout参数不会更改。

这是因为inout不是按引用传递,它只是在函数退出时写入调用方的参数的可变影子副本,而且由于异步函数会立即退出,因此不会回写任何更改。

在下面的SWIFT 2示例中可以看到这一点,其中inout参数允许由转义闭包捕获:

func foo(inout val: String, completion: (String) -> Void) {
    dispatch_async(dispatch_get_main_queue()) {
        val += "foo"
        completion(val)
    }
}
var str = "bar"
foo(&str) {
    print($0) // barfoo
    print(str) // bar
}
print(str) // bar

因为传递给dispatch_async转义函数的生存期。foo,它对val不会被写回来电者的str-只有从传递到完成功能时才能观察到这种变化。

在SWIFT 3,inout参数不再允许由@escaping闭包,这消除了期望引用传递的混淆.。相反,您必须通过复制它,通过将它添加到闭包中捕获列表:

func foo(val: inout String, completion: @escaping (String) -> Void) {
    DispatchQueue.main.async {[val] in // copies val
        var val = val // mutable copy of val
        val += "foo"
        completion(val)
    }
    // mutate val here, otherwise there's no point in it being inout
}

但是,在您的情况下,根本不需要inout。只需将结果数组从请求追加到传递给每个请求的当前结果数组。

例如:

fileprivate func collectAllAvailable(_ storage: [T], nextUrl: String, completion: @escaping CollectAllAvailableCompletion) {
    if let client = self.client {
        let _ : T? = client.collectionItems(nextUrl) { (resultCollection, error) -> Void in

            guard error == nil else {
                completion(nil, error)
                return
            }

            guard let resultCollection = resultCollection, let results = resultCollection.results else {
                completion(nil, NSError.unhandledError(ResultCollection.self))
                return
            }

            let storage = storage + results // copy storage, with results appended onto it.

            if let nextUrlItr = resultCollection.links?.url(self.nextResourse) {
                self.collectAllAvailable(storage, nextUrl: nextUrlItr, completion: completion) 
            } else {
                completion(storage, nil) 
            }
        }
    } else {
        completion(nil, NSError.unhandledError(ResultCollection.self))
    }
}

扫码关注云+社区

领取腾讯云代金券