【问题标题】:JSON seems to execute after all other codeJSON 似乎在所有其他代码之后执行
【发布时间】:2014-10-24 13:08:06
【问题描述】:

以下 Swift 代码必须运行两次才能在标签中显示 JSON 数据。在第一次运行时,标签只是保持空白。在我看来,这个问题可能与最后运行的代码的 JSON 部分类似,但我不知道为什么。我已经包含了下面的代码。我还是个菜鸟,所以要温柔:D

class ViewController: UIViewController {

@IBOutlet weak var labelDegrees: UILabel!
@IBOutlet weak var labelSpeed: UILabel!
override func viewDidLoad() {
    super.viewDidLoad()


    // Set logo in nav bar

    navigationItem.titleView = UIImageView(image: UIImage(named: "logo"))



    // Global save values

    var appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate

    var context: NSManagedObjectContext = appDel.managedObjectContext!



    // JSON Fetching

    let urlPath = "http://api.openweathermap.org/data/2.5/weather?lat=55.564120&lon=12.568605"

    let url = NSURL(string: urlPath)

    let session = NSURLSession.sharedSession()

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

        if (error != nil) {
            println(error)
        }
        else {


            // Delete old entries in CoreData

            var request = NSFetchRequest(entityName: "WindData")

            request.returnsObjectsAsFaults = false

            var results = context.executeFetchRequest(request, error: nil)

            for result in results! {

                context.deleteObject(result as NSManagedObject)
                context.save(nil)

            }

            // Start fetching JSON


            let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary


            var item = jsonResult["wind"] as NSDictionary

            var degrees:Float = item["deg"] as Float
            var speed:Float = item["speed"] as Float


            // Start saving JSON

            var newItem = NSEntityDescription.insertNewObjectForEntityForName("WindData", inManagedObjectContext: context) as NSManagedObject

            var speedValue:Float = speed as Float
            var degreesValue:Float = degrees as Float

            newItem.setValue(speedValue, forKey: "speed")
            newItem.setValue(degreesValue, forKey: "degrees")

            context.save(nil)



        }

    })

    task.resume()

    // Start fetching from CoreData

    var request = NSFetchRequest(entityName: "WindData")

    request.returnsObjectsAsFaults = false

    var results = context.executeFetchRequest(request, error: nil)

    if results!.count > 0 {

        for result in results as [NSManagedObject] {


            let degrees:Float = result.valueForKey("degrees")! as Float
            let speed:Float = result.valueForKey("speed")! as Float

            if speed > 6.0 {

                self.labelDegrees.text = "Go kitesurf: \(speed) m/s"


            }
            else {

                self.labelDegrees.text = "Stay in: \(speed) m/s"


            }


        }
    }
    else {
        println("No data")
    }


}

【问题讨论】:

  • “开始从核心数据获取”之后的代码将在NSURLSession 完成处理程序关闭之前运行之前。这段代码也应该进入闭包。此外,由于该闭包可能不会在主线程上运行,因此不要忘记使用 dispatch_async(dispatch_get_main_queue()) { ... } 将 UI 更新分派回主线程。
  • 谢谢 Rob,这很有道理

标签: ios json xcode swift


【解决方案1】:

您实际上是在使用dataTaskWithURL 在另一个线程上获取数据。因此您需要在dataTaskWithURL 中编写// Start fetching from CoreData 代码。因为dataTaskWithURL 不会立即执行,所以// Start fetching from CoreData 代码将首先被调用,而@ 987654326@正在获取数据。所以用下面的代码补充

class ViewController: UIViewController {

@IBOutlet weak var labelDegrees: UILabel!
@IBOutlet weak var labelSpeed: UILabel!
override func viewDidLoad() {
    super.viewDidLoad()


    // Set logo in nav bar

    navigationItem.titleView = UIImageView(image: UIImage(named: "logo"))



    // Global save values

    var appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate

    var context: NSManagedObjectContext = appDel.managedObjectContext!



    // JSON Fetching

    let urlPath = "http://api.openweathermap.org/data/2.5/weather?lat=55.564120&lon=12.568605"

    let url = NSURL(string: urlPath)

    let session = NSURLSession.sharedSession()
  let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
          dispatch_async(dispatch_get_main_queue(),{
            if (error != nil) {
                println(error)
            }
            else {


                // Delete old entries in CoreData

                var request = NSFetchRequest(entityName: "WindData")

                request.returnsObjectsAsFaults = false

                var results = context.executeFetchRequest(request, error: nil)

                for result in results! {

                    context.deleteObject(result as NSManagedObject)
                    context.save(nil)

                }

                // Start fetching JSON


                let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary


                var item = jsonResult["wind"] as NSDictionary

                var degrees:Float = item["deg"] as Float
                var speed:Float = item["speed"] as Float


                // Start saving JSON

                var newItem = NSEntityDescription.insertNewObjectForEntityForName("WindData", inManagedObjectContext: context) as NSManagedObject

                var speedValue:Float = speed as Float
                var degreesValue:Float = degrees as Float

                newItem.setValue(speedValue, forKey: "speed")
                newItem.setValue(degreesValue, forKey: "degrees")

                context.save(nil)



            }

            // Start fetching from CoreData

            var request = NSFetchRequest(entityName: "WindData")

            request.returnsObjectsAsFaults = false

            var results = context.executeFetchRequest(request, error: nil)

            if results!.count > 0 {

                for result in results as [NSManagedObject] {


                    let degrees:Float = result.valueForKey("degrees")! as Float
                    let speed:Float = result.valueForKey("speed")! as Float


                      if speed > 6.0 {
                         self.labelDegrees.text = "Go kitesurf: \(speed) m/s"
                     }
                     else {
                         self.labelDegrees.text = "Stay in: \(speed) m/s"
                     }

                                       }
            }
            else {
                println("No data")
            }
            });
        })

        task.resume()
}

【讨论】:

  • 记得将 UI 更新(可能还有 CoreData 的东西)发送到主线程。
  • @Rob 除非托管上下文不会被另一个线程调用,否则什么都不会发生。
  • 太棒了。再次感谢!
  • @codester 这就是 Rob 的意思:完成块不会在主线程上调度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 2021-10-02
  • 2017-10-27
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
相关资源
最近更新 更多