在 iOS 上使用 swift 使用 REST API 时出错

Posted

技术标签:

【中文标题】在 iOS 上使用 swift 使用 REST API 时出错【英文标题】:Error consuming REST API using swift on iOS 【发布时间】:2016-03-03 19:51:04 【问题描述】:

我是 ios 开发新手,我一直在学习本教程:https://grokswift.com/simple-rest-with-swift/,但我不知道为什么下面的代码总是返回“占位符”,而且我在控制台的输出中看不到错误:

import Foundation

class Resolver
    func doSomething() -> String
        var result = "the placeholder"
        print("inside doSomething")
        let postEndpoint: String = "http://jsonplaceholder.typicode.com/posts/1"
        guard let url = NSURL(string: postEndpoint) else 
            print("Error: cannot create URL")
            return "error here"
        

        let urlRequest = NSURLRequest(URL: url)

        let config = NSURLSessionConfiguration.defaultSessionConfiguration()

        let session = NSURLSession(configuration: config)
         print("another thing")

        let task = session.dataTaskWithRequest(urlRequest, completionHandler: 
            (data, response, error) in
            guard let responseData = data else 
                print("Error: did not receive data")
                return
                //return "error here"
            
            print("hereeeeeee ############")
            guard error == nil else 
                print("error calling GET on /posts/1")
                print(error)
                return
                //return "error here"
            
            // parse the result as JSON, since that's what the API provides
            let post: NSDictionary
            do 
                post = try NSJSONSerialization.JSONObjectWithData(responseData,
                    options: []) as! NSDictionary
             catch  
                print("error trying to convert data to JSON")
                return
                //return "error here"
            
            // now we have the post, let's just print it to prove we can access it
            print("The post is: " + post.description)
            result = post.description

            // the post object is a dictionary
            // so we just access the title using the "title" key
            // so check for a title and print it if we have one
            if let postTitle = post["title"] as? String 
                print("The title is: " + postTitle)
            

        )
        task.resume()

        return result
        


这是我的 info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleIdentifier</key>
    <string></string>
    <key>CFBundleExecutable</key>
    <string></string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>LSApplicationCategoryType</key>
    <string></string>
    <key>CFBundleName</key>
    <string></string>
    <key>CFBundleDisplayName</key>
    <string></string>
    <key>CFBundleVersion</key>
    <string></string>
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
        <key>NSExceptionDomains</key>
        <dict>
            <key>httpbin.org</key>
            <dict>
                <key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
            <key>jsonplaceholder.typicode.com </key>
            <dict>
                <key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>
    <key>CFBundleShortVersionString</key>
    <string></string>
    <key>CFBundleGetInfoString</key>
    <string></string>
</dict>
</plist>

当我运行测试时,我看到了这个输出:

Test Suite 'RestTest' started at 2016-03-03 15:38:49.364
Test Case '-[FoodTrackerTests.RestTest testResolver]' started.
inside doSomething
another thing
// I want to see the result: the placeholder
Test Case '-[FoodTrackerTests.RestTest testResolver]' passed (0.061 seconds).
Test Suite 'RestTest' passed at 2016-03-03 15:38:49.425.
     Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.062) seconds
Test Suite 'Selected tests' passed at 2016-03-03 15:38:49.426.
     Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.063) seconds

为什么结果变量不包含 post.description 值?

【问题讨论】:

你试过在task里面添加断点吗?为什么它永远不会被调用?你的错误也没有抛出。也许这是因为您正在运行测试并且测试在异步 API 调用之前完成? 我尝试在操场上运行您的代码,但它不会像您发现的那样产生输出。但是,当我在真机上运行它时,它立即运行良好。 @remus 你是对的。测试总是在 http 调用完成之前完成。我不知道您是否必须发布答案才能将其标记为已接受,或者我是否必须自己这样做。 【参考方案1】:

正如 cmets 中所建议的,在返回 HTTP 调用之前测试似乎已经完成(因为 HTTP 请求是异步的),因此在测试运行结束之前您看不到 API 调用的结果。

查看XCAsyncTestCase 并将您的测试设置为等待异步回调。

【讨论】:

【参考方案2】:

doSomething() 方法在异步调用完成之前返回"the placeholder" 值。这就是你看到它的原因。

【讨论】:

以上是关于在 iOS 上使用 swift 使用 REST API 时出错的主要内容,如果未能解决你的问题,请参考以下文章

Swift iOS 应用程序到 REST PHP API - 身份验证的最佳实践是啥?

Swift/iOS8:只允许某些键盘

iOS8/Swift 奇怪的空行为与来自 REST 服务的响应

iOS/Swift:连接 REST API 的良好架构方法

如何在IOS上使用swift防止我的应用程序上的屏幕锁定

如何使用Swift在iOS 8上显示带有文本的活动指示器?