REST API调用无法在swift中运行

时间:2017-07-06 00:32:08

标签: swift rest

我按照本教程在swift中进行简单的REST API调用:https://grokswift.com/simple-rest-with-swift/
我遇到的问题是数据任务完成处理程序接下来会被执行。当我一步一步地调试它时,它只是跳过完成处理程序块。控制台中也没有打印任何内容。
我已经搜索了其他制作REST API调用的方法,但它们都非常类似于这个并且不起作用。

这是我的代码:

    let endpoint: String = "https://jsonplaceholder.typicode.com/todos/1"
    guard let url = URL(string: endpoint) else {
        return
    }
    let urlRequest = URLRequest(url: url)
    let session = URLSession.shared

    let task = session.dataTask(with: urlRequest) { (data, response, error) -> Void in
        guard error == nil else {
            print("Error calling GET")
            return
        }
        guard let responseData = data else {
            print("Error receiving data")
            return
        }
        do {
            print ("Parsing response...")
        }
    }
    task.resume()

2 个答案:

答案 0 :(得分:1)

您的代码对我来说很合适。我在Playground中测试了它,并且我将Parsing response...消息打印到控制台,这使我认为问题出在代码或环境的其他地方。如果您可以发布Github链接或类似内容,我很乐意看看整个项目。

以下是调试此类问题的步骤:

1)确认我的执行环境有一个有效的互联网连接。 Safari应用程序可用于在iOS设备或模拟器上进行确认。可以通过粘贴以下几行来测试运动场。

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
print (try? String(contentsOf: url))

在控制台输出中查找类似于:

的行
Optional("{\n  \"userId\": 1,\n  \"id\": 1,\n  \"title\": \"delectus aut autem\",\n  \"completed\": false\n}")

2)确认网址有效并通过将数据粘贴到网络浏览器网址栏并点击输入来返回数据。您将看到是否在浏览器中打印了JSON。

3)确认我的代码在应用程序运行时实际被调用。您可以使用断点或print()语句执行此操作。正如OOPer2所指出的那样,session.dataTask()中使用的异步回调闭包在与代码的其余部分不同的时间内执行,这就是为什么“它只是跳过完成处理程序块”,同时单步执行使用调试器。您需要在完成处理程序闭包内放置另一个断点或print()语句。我将断点放在guard error == nil else {行。

4)确保在网络请求完成并执行完成处理程序关闭时应用程序仍在执行。如果你的代码在iOS应用程序中运行的ViewController中,它可能很好,但是如果它在Playground中运行它可能不是。默认情况下,Playgrounds在评估完最后一行代码后停止执行,这意味着完成闭包将永远不会执行。您可以通过导入PlaygroundSupport框架并在当前Playground页面上设置needsIndefiniteExecution = true,让Playground无限期地继续执行。将下面的整个代码块粘贴到Playground中以查看它的实际效果:

import Foundation
import PlaygroundSupport

// Keep executing the program after the last line has evaluated so the
// closure can execute when the asynchronous network request finishes.
PlaygroundPage.current.needsIndefiniteExecution = true

// Generic Result enum useful for returning values OR an error from
// asynchronous functions.
enum Result<T> {
    case failure(Error)
    case success(T)
}

// Custom Errors to be returned when something goes wrong.
enum NetworkError: Error {
    case couldNotCreateURL(for: String)
    case didNotReceiveData
}

// Perform network request asynchronous returning the result via a
// completion closure called on the main thread.
//
// In really life the result type will not be a String, it will
// probably be an array of custom structs or similar.
func performNetworkRequest(completion: @escaping (Result<String>)->Void ) {
    let endpoint: String = "https://jsonplaceholder.typicode.com/todos/1"

    guard let url = URL(string: endpoint) else {
        let error = NetworkError.couldNotCreateURL(for: endpoint)
        completion(Result.failure(error))
        return
    }

    let urlRequest = URLRequest(url: url)
    let session = URLSession.shared

    let task = session.dataTask(with: urlRequest) { (data, response, error) -> Void in
        // This closure is still executing on a background thread so
        // don't touch anything related to the UI.
        //
        // Remember to dispatch back to the main thread when calling
        // the completion closure.

        guard error == nil else {
            // Call the completion handler on the main thread.
            DispatchQueue.main.async {
                completion(Result.failure(error!))
            }
            return
        }
        guard let responseData = data else {
            // Call the completion handler on the main thread.
            DispatchQueue.main.async {
                completion(Result.failure(NetworkError.didNotReceiveData))
            }
            return
        }

        // Parse response here...

        // Call the completion handler on the main thread.
        DispatchQueue.main.async {
            completion(Result.success("Sucessfully parsed results"))
        }
    }
    task.resume()
}

performNetworkRequest(completion: { result in
    // The generic Result type makes handling the success and error
    // cases really nice by just using a switch statement.
    switch result {
    case .failure(let error):
        print(error)

    case .success(let parsedResponse):
        print(parsedResponse)
    }
})

答案 1 :(得分:0)

为什么你不使用这个库 Alamofire是一个用Swift编写的HTTP网络库。

将此行添加到 Podfile

    pod 'Alamofire', '~> 4.4'

然后,运行以下命令:

    pod install

然后在 ViewController 文件中:

import Alamofire

Alamofire.request("https://jsonplaceholder.typicode.com/todos/1").responseJSON { response in

     print("Request: \(String(describing: response.request))")   // original url request
     print("Response: \(String(describing: response.response))") // http url response
     print("Result: \(response.result)")                         // response serialization result

     if let json = response.result.value {
        print("JSON: \(json)") // serialized json response
     }

     If let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
       print("Data: \(utf8Text)") // original server data as UTF8 string
     }
}

这里有一个如何解析结果的例子。

https://github.com/CristianCardosoA/JSONParser

有关Alamofire的更多信息:

https://github.com/Alamofire/Alamofire

我希望这有帮助。