Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何将数据从API调用传递到ViewController?_Ios_Swift_Networking - Fatal编程技术网

Ios 如何将数据从API调用传递到ViewController?

Ios 如何将数据从API调用传递到ViewController?,ios,swift,networking,Ios,Swift,Networking,我构建了一个apimager类,该类具有对我的API进行API调用的函数,该API工作正常。然后,我使用一个类APIClient来存储我需要在API上执行的每个调用,这些调用带有特定参数,例如url查询或POST数据 问题是这些函数是空函数,不返回任何内容。我想知道如何修改它以返回可以存储在我的ViewController变量中的数据 以下是我在apimager中使用的函数: func makeRequest(toURL url: URL, withHt

我构建了一个
apimager
类,该类具有对我的API进行API调用的函数,该API工作正常。然后,我使用一个类
APIClient
来存储我需要在API上执行的每个调用,这些调用带有特定参数,例如url查询或POST数据

问题是这些函数是空函数,不返回任何内容。我想知道如何修改它以返回可以存储在我的
ViewController
变量中的数据

以下是我在apimager中使用的函数:

func makeRequest(toURL url: URL,
                     withHttpMethod httpMethod: HttpMethod,
                     completion: @escaping (_ result: Results) -> Void) {
        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
            let targetURL = self?.addURLQueryParameters(toURL: url)
            let httpBody = self?.getHttpBody()
            
            guard let request = self?.prepareRequest(withURL: targetURL, httpBody: httpBody, httpMethod: httpMethod) else
            {
                completion(Results(withError: CustomError.failedToCreateRequest))
                return
            }
            
            let sessionConfiguration = URLSessionConfiguration.default
            let session = URLSession(configuration: sessionConfiguration)
            let task = session.dataTask(with: request) { (data, response, error) in
                completion(Results(withData: data,
                                   response: Response(fromURLResponse: response),
                                   error: error))
            }
            task.resume()
        }
    }
然后在我的ViewController中定义我的
APIClient
,并在点击按钮时调用一个函数:

let apiClient = APIClient()
@IBAction func testTapped(_ sender: Any) {
        apiClient.getData()
    }
然后我的
APIClient
处理调用:

func getData() {
        var decodedResponse: Any?
        guard let url = URL(string: "https://XX.API.XX/XX//XXX/XXX/XXX") else { return }
        apiManager.makeRequest(toURL: url, withHttpMethod: .get) { (results) in
            guard let response = results.response else { return }
            if response.httpStatusCode == 200 {
                guard let data = results.data else { return }
                let decoder = JSONDecoder()
                guard let decodedData = try? decoder.decode(Data.self, from: data) else { return }
            }
        }
    }

有人知道我可以用什么方法修改这些文件,以便从
APIClient
返回
decodedData
并将其存储在我的
ViewController
中吗?

如果需要在视图控制器中获得结果,实现这一点的方法之一是通过回调将其传回,就像你将结果从你的经理传递给APIClient一样

func getData(completion handler: @escaping (Data?, Error?) -> Void) {
        var decodedResponse: Any?
        guard let url = URL(string: "https://XX.API.XX/XX//XXX/XXX/XXX") else { return }
        apiManager.makeRequest(toURL: url, withHttpMethod: .get) { (results) in
            guard let response = results.response else { return }
            if response.httpStatusCode == 200 {
                guard let data = results.data else { return }
                let decoder = JSONDecoder()
                guard let decodedData = try? decoder.decode(Data.self, from: data) else { 
                   handler(NSError(code: 1, ...)) /// <===
                   return
                }
               handler(decodedData)  /// <===
            } else {
               handler(results.error) /// <===
            } 
        }
    }

虽然这可以回答这个问题,但发布“仅代码”答案并不是一个好主意。如果你能解释一下你的代码在做什么,那会更有帮助。我会尝试一下,谢谢。如果你能解释一下你做了些什么,这确实会有帮助,因为我不完全理解你添加的每一个步骤,以及为什么这是解决我问题的好方法。感谢您查看已编辑的应答改进:您不应该为每个请求创建URLSession对象。这是非常非常。。次优;)将其移动到APIManager类,并确保只创建一次。此外,似乎没有必要向全局队列发送消息。如果,那么当APIManager需要同步时,它应该是APIManager创建的专用调度队列。
@IBAction func testTapped(_ sender: Any) {
    apiClient.getData { data, error in
        if let data = data {
             //do anything with the data
        } else if let error = error {
             //show the error message
        }
    }
}