为什么调试器显示变量为空

时间:2016-03-11 11:23:36

标签: ios xcode swift nsurlrequest

我已经向服务器实现了url请求,并使用收到的JSON。 但是我无法解释奇怪的事情。

我的ViewController类:

import UIKit

class TopRatedViewController: UIViewController {

    var importedRates: NSArray = []
    var successfullyConnected: Bool = true


    @IBAction func buttonTapped(sender: AnyObject) {
        print(importedRates)
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: Connection to web service
        let urlString: String = "http://alma.com/get.php"

        let url = NSURL(string: urlString)
        let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: sessionConfig)
        let task = session.dataTaskWithURL(url!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in

            if error != nil {
                self.successfullyConnected = false
            }else {
                var jsonresult = NSArray()
                do {
                    jsonresult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
                        self.importedRates = jsonresult
                } catch _ {
                    print("error loading rates")
                }
            }
        })

        task.resume()
        print(importedRates)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

因此,如果我运行我的应用程序print(importedRates)命令打印空数组。在调试窗口中,我看到其中没有任何内容。

BUT。如果我点击那个应该打印这个变量的按钮 - 它会成功打印一个包含40个元素的数组。 任何人都可以解释为什么它这样工作?

我原本期望这个变量应该用viewdidload方法中的数据填充。

1 个答案:

答案 0 :(得分:1)

您正在viewDidLoad开始异步调用,在完成时设置self.importedRates = jsonresult

completionHandler之后的所有内容都在print(importedRates)之后以非常高的概率执行,更确切地说:当时,网络请求返回(取决于您的网络和请求,一些微秒到几分钟)

这就是按钮按下的原因:当您按下按钮时,请求完成并正确填充数组。

强烈建议不要在主线程上使用同步请求。这可能会导致您的应用无响应(因为所有用户输入都在主线程上处理,并且只要同步呼叫等待响应就无法继续。

相反,如果您期望的数据到达,请从completionHandler内调用视图控制器的方法,该方法使用now-set属性,方式与您希望的方式相同。例如,如果您尝试填充self.tableView : UITableView!

let task = session.dataTaskWithURL(url!, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in

            if error != nil {
                self.successfullyConnected = false
            }else {
                var jsonresult = NSArray()
                do {
                    jsonresult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
                        dispatch_async(dispatch_get_main_queue()) {
                        self.importedRates = jsonresult
                        self.tableView.reloadData() // look here
 }
                } catch _ {
                    print("error loading rates")
                }
            }
        })

        task.resume()