简体   繁体   English

使用异步 function 改变结构属性

[英]Mutating Struct property with asynchronous function

I have the following Struct that I want to initialize, and then use its method query() to mutate its result property.我有以下要初始化的结构,然后使用它的方法 query() 来改变它的结果属性。

Query() sends and fetches JSON data, then decodes it to a String. Query() 发送并获取 JSON 数据,然后将其解码为字符串。 When I declare query() as a mutating function, I receive the error "Escaping closure captures mutating 'self' parameter" in my URLSession.当我将 query() 声明为变异 function 时,我在我的 URLSession 中收到错误“转义闭包捕获变异 'self' 参数”。

What do I need to change?我需要改变什么?

The call:来电:

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

The struct:结构:

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 error: Xcode 错误: 在此处输入图像描述

There are many issues in the code.代码中有很多问题。

The most significant issue is that the URLRequest is asynchronous.最重要的问题是URLRequest是异步的。 Even if no error occurred result will be always empty.即使没有发生错误, result也将始终为空。

You have to add a completion handler – it fixes the errors you got by the way – and it's highly recommended to handle all errors .你必须添加一个完成处理程序——它修复了你顺便得到的错误——强烈建议处理所有错误

Instead of JSONSerialization the code uses JSONDe/Encoder代码使用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)
        }
    }
}

Both exclamation marks ( ! ) are safe.两个感叹号 ( ! ) 都是安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM