Swift 5:转义闭包捕获'inout'参数

Posted

技术标签:

【中文标题】Swift 5:转义闭包捕获\'inout\'参数【英文标题】:Swift 5 : Escaping closure captures 'inout' parameterSwift 5:转义闭包捕获'inout'参数 【发布时间】:2020-01-28 06:07:41 【问题描述】:

我已经有了从服务器收到的响应数据。此响应数据有一些面包师数据。

现在我想计算用户和面包店的距离,然后将其存储在同一个模态类中。我为它创建了一个函数。并且由于这个功能需要在4,5个视图控制器中使用,我的计划是创建作为UIViewController的扩展

func getDistanceUserBakery(bakeryData : inout [BakeryRecord], completion : @escaping (Int?) -> () ) 

    for index in 0...(bakeryData.count-1) 
        //1
        let googleApiAdd = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&"
        //2
        let origin = "origins=\(UserLocation.coordinates.latitude),\(UserLocation.coordinates.longitude)"
        //3
        let destination = "&destinations=\(bakeryData[index].location?.coordinates?[1] ?? 0.0),\(bakeryData[index].location?.coordinates?[0] ?? 0.0)"
        //4
        let googleKey = "&key=\(GOOGLE_KEY)"
        //5
        let url = googleApiAdd + origin + destination + googleKey

        let request = URLRequest(url: URL(string: url)!)

        //6 - this line is showing the error.

        let task = URLSession.shared.dataTask(with: request) (data, response, error) in
            guard let data = data else 
                completion(nil)
                Toast.show(message: "Unable to calculate distance from user to bakery", controller: self)
                return 
            let stringResponse = String(data: data, encoding: .utf8)!
            let dictData = stringResponse.convertToDictionary()
            do 
                let jsonData = try JSONSerialization.data(withJSONObject: dictData as Any, options: .prettyPrinted)
                let decoder = JSONDecoder()
                let model = try decoder.decode(GoogleDistance.self, from: jsonData)
                bakeryData[index].disanceInMiles = model.rows?[0].elements?[0].distance?.text ?? "NaN"
                completion(index)
             catch let parsingError 
                print("Error data :", parsingError)
                completion(nil)
            
        
        task.resume()
    

这就是我从服务器接收到数据后调用此函数的方式,

  self.getDistanceUserBakery(bakeryData: &self.bakeryData)  index in
                    if index != nil 
                        DispatchQueue.main.async 
                            // here I am thinking as the bakeryData will hold the new value for distanceInMiles, the collectionView will start showing up that result on reload.
                            self.resultCollection.reloadItems(at: [IndexPath(item: index!, section: 0)])
                        
                    
                

现在的问题:

据我所知,当您将参数作为 inout 传递时,可以从函数内部更改值,而这些更改会反映在函数外部的原始值中。

但是当我尝试代码时,它说转义闭包捕获'inout'参数'bakeryData'。在我的代码中,//6 正在产生错误。

如何解决这个错误?

【问题讨论】:

你的答案在这里***.com/questions/39569114/…,如果有帮助请投票 我首先要说 UIViewController 的扩展在这里不是正确的方法。此代码应该在您的数据模型或类似的。另外,你为什么使用inout 参数?您需要有充分的理由使用inout 参数。 如果它是一个结构,那么您当前的方法无论如何都不会起作用 - 结构是不可变的,所以 bakeryData[index].disanceInMiles 应该给您一个错误。如果您将BakerData 设为类,则该数组包含引用类型,您可以更新元素的属性。 之所以有效,是因为您没有修改数组,而只是修改了数组中的一个元素。如果你说someArray[index] = something 你正在修改数组。说someArray[index].someProperty = somethingElse 你没有修改数组,只要数组包含引用对象(类实例),即使你修改了数组,也没关系 - 数组中只有一个事物的实例在每个索引处 @mutAnT 嗯,不知道为什么,但我从未尝试过带有完成的 for 循环,并等待它完成多次。如果有效,那就没问题了。 【参考方案1】:

正如@Paulw11 在 cmets 中建议的那样,

BakeryData 是一个结构吗?如果是这样,那么只需将其设为一个类。如果你做 BakerData 一个类然后数组包含引用类型,你可以 更新元素的属性

我将结构更改为类,它确实有效。

【讨论】:

以上是关于Swift 5:转义闭包捕获'inout'参数的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3.0 错误:转义闭包只能按值显式捕获 inout 参数

Swift 4:转义闭包只能通过值显式捕获 inout 参数

转义闭包捕获 Swift 中的变异“self”参数错误

转义闭包捕获变异的“自我”参数,Firebase

转义闭包捕获非转义参数“函数” Xcode 说

错误:转义闭包捕获变异的“自我”参数