2

I collected JSON data from an API and am able to initialize my array (class instance variable), but after the block, data is destroyed from array. How can I return data from the task block that can be used to initialize my array?

override func viewDidLoad() {
    // var movies=[Movie]()

    let requestURL: NSURL = NSURL(string: "https://yts.ag/api/v2/list_movies.json")!
    let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(urlRequest) {
        (data, response, error) -> Void in

        let httpResponse = response as! NSHTTPURLResponse
        let statusCode = httpResponse.statusCode
        if (statusCode == 200) {
            print("File downloaded successfully.")
            do {
                let jsonYts = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)

                let jsonDataTag = jsonYts["data"]
                let jsonMovie = jsonDataTag!!["movies"]!

                let movies = [Movie].fromJSONArray(jsonMovie as! [JSON])

                // self.moviesList = movies as! [Movie] // this is my array. I want to add data to it

                for data in self.moviesList {
                    // print(data.title)
                }  
            } catch {

            }
        }
    }

    task.resume()       
}
BaseZen
  • 8,650
  • 3
  • 35
  • 47
Ayaz Ahmad Tarar
  • 534
  • 8
  • 24
  • 5
    Take example in my answer here: http://stackoverflow.com/questions/37340967/json-parsing-swift-array-has-no-value-outside-nsurlsession – Eric Aya Aug 04 '16 at 17:11

2 Answers2

0

Asynchronous methods don't return to the invoking function because they are not called directly in the first place. They are placed on a task queue to be called later (on a different thread!). It's the hardest thing for those new to asynchronous programming to master. Your async method must mutate a class variable. So you'll have:

class MyContainer: UIViewController {
    var myInstanceData: [SomeObject] // In your case moviesList

    func startAsyncRequest() { // In your case viewDidLoad()
        // In your case NSMutableURLRequest
        doSomethingAsynchronous(callback: { [weak self] (result) in
            // in your case JSON parsing
            self?.myInstanceData = parseResult(result) // share it back to the containing class
            // This method returns nothing; it is not called until well
            // after startAsyncRequest() has returned
        })
    }
}

Once the callback finishes, myInstanceData is available to all the other methods in the class. Does that make sense as a general pattern?

After that you have to learn this material:

Swift performSegueWithIdentifier not working

To get the result back into the UI from the background thread on which your callback runs.

Addendum Taking a second look after editing your question for clarity, it seems you may already know this, but you've commented out the correct line, and if you put it back in, things just work, that is, the movies won't be destroyed but will be recorded in the class property moviesList.

           // self.moviesList = movies as! [Movie] // this is my array. I want to add data to it

Why not just re-enable it? Perhaps the real problem is: Do you mean to append instead of overwrite, perhaps? Then the answer may be as simple as:

self.moviesList += movies as! [Movie]
Community
  • 1
  • 1
BaseZen
  • 8,650
  • 3
  • 35
  • 47
  • I think the question as phrased is misleading and pulls in two directions so please clarify based on which part of the above answer actually resolves it. – BaseZen Aug 04 '16 at 17:36
-1

You can just use "SwiftyJson" to handle the response from the API if it returns JSON data; if it uses XML then use "SWXMLHash". They are both pods (libraries) designed to handle the response from their respective formats.

Installation help for SwiftyJson. If you still have problems comment below.

At this point you can just import SwiftyJson and use it.

Let response be any object, and suppose your JSON data is in this format:

{"text": {
        "data": "Click Here",
        "size": 36,
        "style": "bold",
        "name": "text1",
        "hOffset": 250,
        "vOffset": 100,
        "alignment": "center"
    }
}

Then you can just write code like this

func response(data){

   let dt = JSON(data : data) // the second data is the response from api

   response = dt.object   // for accessing the values as object from json format

   let style = response["text"]["data"]!! as? String   // style = "bold" 

   let n = response["text"]["name"]!! as? String       // n = "text1"

   let size = response["text"]["hOffset"]!! as? Int    // size = 250
}


 // Done !! Easy.. if you guys need help or snapshots for the same do comment.. 
Dan Oberlam
  • 2,435
  • 9
  • 36
  • 54