iosswiftwebapi

Setting properties in init method using closures


I'm hitting a web API to access some JSON and initialize a GRDMovie object. While that is going on, I need to hit the API using a different URL for some of the other properties. This is causing some issues in the GRDMovie init method, since the closures are getting skipped over. Code below:

var posterImage : UIImage?
let title : String
let score : Double
var rating : String?
let releaseDate : String
let overview : String
let movieID : Int
let smallURL : String
let year : String

init(title:String, overview:String, score:Double, movieID:Int, releaseDate:String, smallURL: String, year:String) {

    self.title = title
    self.overview = overview
    self.score = score
    self.movieID = movieID
    self.releaseDate = releaseDate
    self.smallURL = smallURL
    self.year = year
    self.rating = nil
    self.posterImage = nil


    self.getMovieRatingWith(movieID) { (rating) in
        self.rating = rating
    }

    self.getPosterImageDataFromURL(smallURL) { (posterImage) in
        self.posterImage = posterImage
    }
}

func getMovieRatingWith(movieID: Int, completion: (rating: String) -> ()) {

    var apiDict = NSDictionary()
    var rating: String = ""

    let urlString:String = "http://api.themoviedb.org/3/movie/\(movieID)?api_key=ebea8cfca72fdff8d2624ad7bbf78e4c&append_to_response=releases"
    let escapedUrlString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
    let apiURL = NSURL(string:escapedUrlString!)
    let session = NSURLSession.sharedSession()

    session.dataTaskWithURL(apiURL!, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
        do {
            if let data2 = data {
                let jsonDict = try NSJSONSerialization.JSONObjectWithData(data2, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
                //send json outward
                apiDict = jsonDict

                if let releases = apiDict["releases"] as? NSDictionary {
                    if let countries = releases["countries"] as? [NSDictionary] {
                        for countryData in countries {
                            if let place: String = countryData["iso_3166_1"] as? String {
                                if place == "US" {
                                    rating = countryData["certification"] as! String
                                } else {

                                }
                            }
                        }
                    }
                }

                if rating == "" {
                    rating = "Not Available"
                }

                completion(rating: rating)
                //print(rating)
            }
        } catch {
            //handle NSError
            print("error")
        }
    }).resume()
}

func getPosterImageDataFromURL(smallURL:String, completion: (posterImage: UIImage) -> ()) {

    let escapedURLString:String = smallURL.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
    let callURL = NSURL(string: escapedURLString)
    let session = NSURLSession.sharedSession()

    session.dataTaskWithURL(callURL!) { (data:NSData?, response:NSURLResponse?, error:NSError?) in
        do {
            if let data2 = data {
                let poster = UIImage(data: data2)
                completion(posterImage: poster!)
            }
        }
    }

}

Naturally I'm getting nil for posterImage and rating. How do I structure this in order to properly capture these values?


Solution

  • I think its better to do the api call in the controller instead. You can either create an obj first, or create it after the api callback depends on what you want.

    If you want to create the obj first, you do this below.

    In GRDMovieController.swift (I just name it randomly) :

    let obj : GRDMovie?
    

    In somewhere init the obj and call the api to get data :

    obj = GRDMovie(title, overview: overview, score: score, movieID: id, releaseDate: date, smallURL: url, year: year)
    getMovieRatingWith(obj)
    getPosterImageDataFromURL(obj)
    

    And the functions can be something like this:

    func getMovieRatingWith(movieObj: GDVMovie) {
        var apiDict = NSDictionary()
        var rating: String = ""
    
        let urlString:String = "http://api.themoviedb.org/3/movie/\(movieObj.movieID)?api_key=ebea8cfca72fdff8d2624ad7bbf78e4c&append_to_response=releases"
        let escapedUrlString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
        let apiURL = NSURL(string:escapedUrlString!)
        let session = NSURLSession.sharedSession()
    
        session.dataTaskWithURL(apiURL!, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
            do {
                if let data2 = data {
                    let jsonDict = try NSJSONSerialization.JSONObjectWithData(data2, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
                    //send json outward
                    apiDict = jsonDict
    
                    if let releases = apiDict["releases"] as? NSDictionary {
                        if let countries = releases["countries"] as? [NSDictionary] {
                            for countryData in countries {
                                if let place: String = countryData["iso_3166_1"] as? String {
                                    if place == "US" {
                                        rating = countryData["certification"] as! String
                                    } else {
    
                                    }
                                }
                            }
                        }
                    }
    
                    if rating == "" {
                        rating = "Not Available"
                    }
    
                    movieObj.rating = rating
    
                    //print(rating)
                }
            } catch {
                //handle NSError
                print("error")
            }
        }).resume()
    }
    
    func getPosterImageDataFromURL(movieObj: GRDMovie) {
    
        let escapedURLString:String = movieObj.smallURL.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
        let callURL = NSURL(string: escapedURLString)
        let session = NSURLSession.sharedSession()
    
        session.dataTaskWithURL(callURL!) { (data:NSData?, response:NSURLResponse?, error:NSError?) in
            do {
                if let data2 = data {
                    let poster = UIImage(data: data2)
                    movieObj.posterImage = poster
                }
            }
        }
    
    }
    

    Please correct me if I am wrong and hope this will help.