Swift转义关闭未执行

时间:2017-12-11 23:34:07

标签: ios swift

我想使用转义关闭来执行一些代码,但它无法正常工作。你能告诉我这个例子有什么问题吗?

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print("Calling getData")
        getData(completion: {
            print("Escaping closure getData")
        })

        print("Returning from getData")

        print("Calling doSomething")
        doSomething (completion: {
            print("Escaping closure doSomething")
        })
        print("Returning from doSomething")
    }

    func getData(completion: @escaping () ->Void)
    {
        print ("Begin getData")
        var request = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com")!)
        request.httpMethod = "GET"

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let session = URLSession.shared
        let task = session.dataTask(with: request) { (data, response, error)  in
            print ("Escaping closure dataTask")

            guard error == nil else {
                print("Error calling GET API: \(error!)")
                return
            }
        }
        task.resume()
        print ("Ending getData")
    }

    func doSomething(completion: @escaping () ->Void)
    {
        print ("Begin doSomething")
        sleep(3)
        print ("Ending doSomething")
    }
}

print("Escaping closure getData")print("Escaping closure doSomething")永远不会被执行。

2 个答案:

答案 0 :(得分:1)

主要问题是你从未真正调用函数内的闭包。

func getData(completion: @escaping () ->Void){
    print ("Begin getData")
    var request = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com")!)
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")

    let session = URLSession.shared
    let task = session.dataTask(with: request) { (data, response, error)  in
        print ("Escaping closure dataTask")

        guard error == nil else {
            print("Error calling GET API: \(error!)")
            return
        }
        print ("Ending getData")
        completion()
    }
    task.resume()
}

其他一些通用问题:print ("Ending getData")应该在URLSession.dataTask(with:)的完成处理程序中,否则它将在网络请求实际完成执行之前被调用。

您不应该使用sleep(),因为它也会阻止主线程,因此会使您的整个应用无响应。

您很少想要空的完成处理程序。你通常会实现的是一个带有两个或多个可选输入参数的闭包,每个返回值一个,错误一个。

func getData(completion: @escaping (Data?,Error?) ->Void){
        var request = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com")!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let session = URLSession.shared
        let task = session.dataTask(with: request) { (data, response, error)  in
            guard error == nil, let data = data else {
                completion(nil,error)
                return
            } 
            //In general you would also convert `data` into a more suitable format, in your case, you would deserialize the JSON
            completion(data,nil)
        }
        task.resume()
    }

然后这样称呼:

getData({ data, error in
    guard error == nil, let data = data else {
        //handle the error here
        return
    }
    //use the value from the network request
})

答案 1 :(得分:0)

完成异步任务后,您必须调用completion个关闭。例如,您的getData应该更像这样:

func getData(completion: @escaping () ->Void) {
    print ("Begin getData")
    var request = URLRequest(url: URL(string: "https://jsonplaceholder.typicode.com")!)
    request.httpMethod = "GET"

    request.addValue("application/json", forHTTPHeaderField: "Content-Type")

    let session = URLSession.shared
    let task = session.dataTask(with: request) { (data, response, error)  in
        print ("Escaping closure dataTask")

        guard error == nil else {
            print("Error calling GET API: \(error!)")
            completion()  //-------Here, before returning
            return
        }
        completion()  //--------Here, after your task is done (and error free)
    }
    task.resume()
    print ("Ending getData")
}