【问题标题】:Wait response before proceeding在继续之前等待响应
【发布时间】:2018-02-19 16:08:37
【问题描述】:

我正在使用 iOS Swift 应用程序,我正在尝试获取网站的内容。问题是,当我运行代码时,响应对象是在执行其他行之后返回的。

我有这个:

public var response: Array<Any>?

public func myRequest(completion: @escaping (_ json: Any?, _ error: Error?)->()) {
    var request = URLRequest(url: self.url)
    request.httpBody = postString.data(using: .utf8)
    let t = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data,
        error == nil else {
            completion(nil, error)
            return
        }
        let json = try? JSONSerialization.jsonObject(with: data, options: [])
        if let dictionary = json as? [String : Any] {
            if (dictionary["ok"] as? String == "true") {
                self.response = dictionary["users"] as? Array<Any>
            }
        }
        completion(json, error)
    }
    t.resume()
}

然后:

func foo() {
    myRequest() { json, error in
        print(json)
    }
    print("I'm here!")
}

我得到了这个:

I'm here
{...} //JSON

问题是:为什么我在JSON 之前检索I'm here?我该如何解决?

【问题讨论】:

  • 请,不要那样做。使用某种完成处理程序。
  • 永远不要不要在这种情况下使用“睡眠”。不要等。使用回调。这是你应该做什么的一个例子:stackoverflow.com/a/37343547/2227743 另一个:stackoverflow.com/a/31264556/2227743 关于这个问题还有很多很多其他的现有答案。搜索“回调”、“异步”和“完成处理程序”。
  • @the4kman 我知道这是一件坏事事实上我的问题是:“我怎么能不使用 sleep()?”

标签: swift nsurlsession nsurlrequest


【解决方案1】:

这是一个示例(基于您的代码),说明如何让 myRequest 接受完成块并在 JSON 被反序列化(或不被反序列化)后调用它。

public func myRequest(completion: @escaping (_ json: Any?, _ error: Error?)->())
{
    var request = URLRequest(url: self.url)
    request.httpBody = postString.data(using: .utf8)
    let t = URLSession.shared.dataTask(with: request) 
    { data, response, error in
        guard let data = data,
                  error == nil else
        {
            completion(nil, error)
            return
        }
        let json = try? JSONSerialization.jsonObject(with: data, options: [])
        //Do other things
        completion(json, error)
    }
    t.resume()
}

你可以这样称呼它:

func foo()
{
    myRequest()
        { json, error in
            // will be called at either completion or at an error.
        }
}

现在,如果您不在主线程上,并且真的想等待您的 myRequest() 完成,那么方法如下(顺便说一句,有很多方法可以做到):

func foo()
{
    let group = DispatchGroup()
    group.enter()

    myRequest()
        { json, error in
            // will be called at either completion or at an error.
            group.leave()
        }
    group.wait() // blocks current queue so beware!
}

【讨论】:

  • 完成闭包中的下划线字符(实际上也是参数标签)在 Swift 3+ 中毫无意义
  • @vadian 它们有一点:它们使方法更具可读性,因此您无需提供方法注释或期望调用者挖掘您的方法只是为了弄清楚完成的参数真的是。总是像其他人要使用它一样编写代码是件好事。另外,提供标签使编写方法注释更容易,因为注释文本可以通过名称引用它们。
  • 我主要指的是下划线字符。它们是 Swift 2 遗留的,在闭包调用中使用(或可以省略)参数标签。
  • 下划线是必需的,至少在 Swift 4 中,只要提供标签。否则你会得到一个编译错误,例如:“函数类型不能有参数标签;在'json'之前使用'_'”
  • @Smartcat 我试过了,但它不起作用。当foo() 被执行时,脚本继续并执行foo() 之后的所有行。问题依旧:执行其他代码后返回响应(json)。
猜你喜欢
  • 1970-01-01
  • 2023-01-17
  • 2020-01-18
  • 2014-07-12
  • 2016-04-02
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 2020-03-11
相关资源
最近更新 更多