【问题标题】:How to return an object from a method that contains a DataTask [duplicate]如何从包含 DataTask 的方法返回对象 [重复]
【发布时间】:2018-04-25 19:19:06
【问题描述】:

我是 swift 新手,正在尝试做类似的事情:

我有一个名为 Api Response 的结构:

struct ApiResponse {
    var IsSuccess : Bool = false
    var Message : String?
    var ReturnedData : Data?
}

在另一个名为 CommonHandler 的类中有一个函数,可以调用 api

public class CommonHandler {

    public func CallApi(_ apiUrl : String , _ parameters : [String : Any] ) -> ApiResponse
    {
        var apiResponse = ApiResponse()

        let url = URL(string: apiUrl)!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)

        let task = URLSession.shared.dataTask(with: request , completionHandler : { data, response, error in
            if let error = error {
                // handle the transport error
                return
            }
            guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                // handle the server error
                return
            }
            apiResponse.ReturnedData = data
            apiResponse.IsSuccess = true
            apiResponse.Message = "Succeed"

        })
        task.resume()

        return apiResponse
    }
}

我想像这样在 UIViewController 中调用这个函数:

var handler = CommonHandler()
let param :[String : String] = ["param":"param"]
let url = "url"

let response = handler.CallApi(url, param)
print(response.IsSuccess)
print(response.Message!)

我知道我不能像这样使用 dataTask 方法。它是异步的。 但是我怎样才能在一个非 void func 中调用 api 并返回它的响应数据呢? 然后我将 ReturnedData json 解析为 struct。 在这种情况下最好的方法是什么? 谢谢

【问题讨论】:

标签: swift nsurlsession


【解决方案1】:

使用异步完成处理程序

public func callApi(with url : String , parameters : [String : Any], completion: @escaping (ApiResponse?) -> () )
{
    var apiResponse = ApiResponse()

    let url = URL(string: apiUrl)!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)

    let task = URLSession.shared.dataTask(with: request , completionHandler : { data, response, error in
        if let error = error {
            // handle the transport error
            completion(nil)
            return
        }
        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            // handle the server error
            completion(nil)
            return
        }
        apiResponse.ReturnedData = data
        apiResponse.IsSuccess = true
        apiResponse.Message = "Succeed"
        completion(apiResponse)

    })
    task.resume()
}

然后调用它:

var handler = CommonHandler()
let param = ["param":"param"]
let url = "url"

handler.callApi(with: url, parameters: param) { response in
    if let response = response {
       print(response.IsSuccess)
       print(response.Message!)
    }
}

注意:

请遵守变量和函数名称以小写字母开头的命名约定,并使用参数标签以提高可读性。

【讨论】:

  • 感谢您的回复。这对我有用。这是导致 UI 冻结吗?我应该使用这种方法吗?我只是想防止在 api 调用上重复代码
  • 它不会冻结 UI 或当前线程,这是处理异步 API 调用的推荐方法。如果涉及 UI,请确保 UI 在主线程上更新(也是异步的)。并注意保持对包含异步任务的类的强引用,直到它完成。
  • 使用完成处理程序是一个非常好的方法,但是您应该记住它会破坏流程并且有时可能不是您需要的。具体来说,当您需要在相同的上下文/线程/范围内执行一组操作时,这不是一个选项。但是对于琐碎的网络操作来说,我相信它比 GCD 更好。
  • @Hexfire 我不同意它破坏了流程的说法。一个软件中的流程与代码中的出现顺序无关。许多任务基于异步执行。由开发人员来理解和使用这些模式。通知总是比轮询好。 不要问,要告诉!
  • @vadian 我没有将 flow 称为任何特殊的技术术语。我立即在评论中解释了它。当执行顺序很重要时(将事物保持在范围、上下文(例如,在使用 DB 上下文时)或线程时),方法会有所不同 肯定。因此,通知绝对不是总是更好,而是取决于特定的需要。但我同意你的观点,对于大量任务(例如,有问题的任务)来说,通知是干净且好的。
猜你喜欢
  • 1970-01-01
  • 2019-02-12
  • 2013-11-28
  • 2018-06-02
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
相关资源
最近更新 更多