【问题标题】:Mutating Struct property with asynchronous function使用异步函数改变结构属性
【发布时间】:2021-06-29 22:20:40
【问题描述】:

我想要初始化以下结构,然后使用它的方法 query() 来改变它的结果属性。

Query() 发送和获取 JSON 数据,然后将其解码为字符串。当我将 query() 声明为变异函数时,我在我的 URLSession 中收到错误“转义闭包捕获变异 'self' 参数”。

我需要改变什么?

电话:

var translation = Translate(string: "hello", base: "en", target: "de", result: "")
translation.query()
let translated = translation.result

结构:

struct Translate {
    
    let string: String, base: String, target: String
    var result: String
    
    mutating func query() {
        
        let body: [String: String] = ["q": self.string, "source": self.base, "target": self.target]
        let bodyData = try? JSONSerialization.data(withJSONObject: body)

        guard let url = URL(string: "https://libretranslate.com/translate") else { return }
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        
        request.httpBody = bodyData
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            
            guard let data = data, error == nil else {
                print(error?.localizedDescription ?? "No data")
                return
            }
            
            DispatchQueue.main.async {
                let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
                if let responseJSON = responseJSON as? [String: Any] {
                    if responseJSON["translatedText"] != nil {
                        self.result = responseJSON["translatedText"] as! String
                    }
                }
            }
            
            return
            
        }
        .resume()
        
    }
    
}

Xcode 错误:

【问题讨论】:

  • 我通读了这篇文章,它确实有助于解决错误,首先将 JSON 响应分配给 query() 中的属性,然后将其分配给 Struct 中的属性。然而,这不会异步工作,所以结果总是什么都没有。

标签: swift


【解决方案1】:

代码有很多问题。

最重要的问题是URLRequest 是异步的。即使没有发生错误,result 也将始终为空。

你必须添加一个完成处理程序——它修复了你顺便遇到的错误——强烈建议处理所有错误

代码使用JSONDe/Encoder而不是JSONSerialization

struct Translation : Decodable { let translatedText : String }

struct Translate {
    
    let string: String, base: String, target: String
    
    func query(completion: @escaping (Result<String,Error>) -> Void) {
        
        let body: [String: String] = ["q": self.string, "source": self.base, "target": self.target]
        do {
            let bodyData = try JSONEncoder().encode(body)
            
            let url = URL(string: "https://libretranslate.com/translate")!
            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            
            request.httpBody = bodyData
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
            
            URLSession.shared.dataTask(with: request) { data, response, error in
                if let error = error { completion(.failure(error)); return }                                       
                completion( Result{ try JSONDecoder().decode(Translation.self, from: data!).translatedText} )
            }                
            .resume()
        } catch {
            completion(.failure(error))
        }
    }
}

let translation = Translate(string: "hello", base: "en", target: "de")
translation.query() { result in
    DispatchQueue.main.async {
        switch result {
            case .success(let translated): print(translated)
            case .failure(let error): print(error)
        }
    }
}

两个感叹号 (!) 都是安全的。

【讨论】:

  • 注意在错误情况和成功情况下在不同线程上调用完成块。这可能是错误的来源。调用者可能没有预料到这种行为
  • @Shadowrun 你完全正确,谢谢。我编辑了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多