pennyloaf pennyloaf - 7 months ago 9
Swift Question

Swift - 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?

Answer

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.

Comments