1

I'm developing an application what's based on JSON objects requested from specified URL but sometimes (not every time) I get no result
Gonna show some code snippets that can help determining this simple (?) problem
I have an array called "Data" (var Data:[String] = []) in my class MyTestClass and the following function:

func loadData(onComplete: ([String]) -> ()) {
        // Declaring a local array
        var Local:[String] = []

        // Preparing JSON request
        let address = "<URL goes here>"
        let url = NSURL(string: address)
        let request = NSURLRequest(URL: url!)

        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(request) { (data, response, error) in
            if (data?.length > 0 && error == nil) {
                let responseData = data as NSData!

                if responseData == nil {
                    // Presenting some alert
                } else {
                    let jsonObject: AnyObject? = try? NSJSONSerialization.JSONObjectWithData(responseData!, options: NSJSONReadingOptions.MutableContainers)

                    if jsonObject == nil {
                        // Presenting some alert
                    } else {
                        let json: NSArray = jsonObject as! NSArray

                        for (var i = 0; i < json.count; i++) {
                            if let obj = json[i] as? NSDictionary {
                                if let m = obj["m"] as? String {
                                    if m != "Unknown" {
                                        Local.append(m)
                                    }
                                }
                            }
                        }

                        onComplete(Local)
                    }

                }
            } else if error != nil {
                NSLog("Error: %@", error!)
            }
        }

        // Starting task
        task.resume()
    }

In viewDidLoad() I'm doing the following:

// Loading data
loadData { (d) in
    for dat in d {
        self.Data.append(dat)
    }
}

I'm using this solution (the functions are 100% the same [CTRL+C / CTRL+V]) in every of my ViewControllers, my hierarchy is the following: Table1 -> Table2 -> Table3

Table1 works fine, has no problem, displays the results every time fine, Table2 works most of the time (sometimes very rarely displays no result) but Table3 goes crazy ~80% of the time.

I'm getting mad because of this thing happening to me, before iOS 9 I used synchronous calls and had no problems because it's a small application, but now I don't even know how to make it work with this session.dataTaskWithRequest... thing.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Szilárd Dóró
  • 93
  • 1
  • 10
  • As an aside, I'd suggest following Cocoa naming conventions and start all of your variables with lowercase letters. Also "data" is misleading, because, by convention, that sort of name tends to be used with `NSData` objects. I might suggest `strings` (or, even better, something that suggests what sort of strings those are) instead of `Data`. – Rob Oct 08 '15 at 22:04
  • 1
    I was just using that name as an example for my problem, in my real application it's different but thanks for suggestion. – Szilárd Dóró Oct 08 '15 at 22:05

2 Answers2

2

You need to use dispatch async and reload the data of the table view on completion of your loadData block

use dispatch async with dataTaskWithRequest

Community
  • 1
  • 1
matanwrites
  • 812
  • 1
  • 10
  • 18
  • Thank you, it's working now, but I have an other similar question. What if I'm working with structures? How to load them properly? `struct Information { var x = String() var y = String() var z = String() }` I'm using the same method as above to get data from web and pass it through onComplete, but the data seems lost. – Szilárd Dóró Oct 08 '15 at 22:01
  • 1
    The process is largely the same. Just make sure you call `reloadData` (and do all of that on the main queue) and it should be fine. By the way, I might suggest `struct Information { var x : String var y : String var z : String }` and then using `Information(x: a, y: b, z: c)` (where `a`, `b`, and `c` would be your strings). If that's not working, create new question with [example](http://stackoverflow.com/help/mcve). – Rob Oct 08 '15 at 22:12
  • And you would need to change the type of the `Local` variable to return your structure – matanwrites Oct 08 '15 at 22:19
1

You should call tableView.reloadData() (from the main queue) the request is done, after you're done appending all of those strings to your array.

loadData { (d) in
    dispatch_async(dispatch_get_main_queue()) {
        for dat in d {
            self.Data.append(dat)
        }
        self.tableView.reloadData()
    }
}

For the record, it's excellent that you have retired the synchronous network calls. The synchronous calls may have been easy, but they can cause problems.

Rob
  • 415,655
  • 72
  • 787
  • 1,044