iosjsonswiftalamofire

Is this function right? Call a function with closure (swift - iOS)


The Problem

I have to search a movie on the API and return on my table view the movies searched.

Language

Swift 3 - xcode 8

Function to get Json from API

func searchMoviesOnJson(imdbTitle: String, completionHandler: @escaping (Dictionary<String, Any>?) -> ()) {

let urlByName: String = "https://www.omdbapi.com/?s=\(imdbTitle)&type=movie"

//returns a list of movies that contains the title searched
//------------------------------------------------


Alamofire.request(urlByName).responseJSON {
    response in

    switch response.result {

    case .success(let value):
        let moviesJSON = value
        completionHandler(moviesJSON as? Dictionary<String, Any>)

    case .failure(_):
        completionHandler(nil)
    }
}
//------------------------------------------------

This class called Movie (that will be searched on the API):

class Movie {

var poster: String?
var title : String?
var year  : String?
var imdbID: String?


init(poster: String?, title: String?, year: String?, imdbID: String?) {

    if let isPoster = poster { self.poster = isPoster }
    else { self.poster = nil }

    if let isTitle = title { self.title = isTitle }
    else { self.title = nil }

    if let isYear = year { self.year = isYear }
    else { self.year = nil }

    if let isImdbID = imdbID { self.imdbID = isImdbID }
    else { self.imdbID = nil }

  }
}

And then, my DAO:

class MovieDAO {


//Search By Title

static func getMovies(imdbTitle: String, completionHandler: @escaping (([Movie]) -> ())) {

    searchMoviesOnJson(imdbTitle: imdbTitle, completionHandler: {
      newMoviesJSON in

        if let moviesJSON = newMoviesJSON {

            if moviesJSON["Error"] != nil { return }

            else {

                //casting
                let arrayOfMovies: [[String : String]] = newMoviesJSON!["Search"] as! [[String : String]]

                var fetchedMovies = [Movie]()

                for eachFetchedMovie: [String : String] in arrayOfMovies {

                    var poster: String?
                    var title : String?
                    var year  : String?
                    var imdbID: String?

                    if let isPoster = eachFetchedMovie["Poster"] { poster = isPoster }
                    else { poster = nil }

                    if let isTitle = eachFetchedMovie["Title"] { title = isTitle }
                    else { title = nil }

                    if let isYear = eachFetchedMovie["Year"] { year = isYear }
                    else { year = nil }

                    if let isImdbID = eachFetchedMovie["imdbID"] { imdbID = isImdbID }
                    else { imdbID = nil }

                    let movie: Movie = Movie(poster: poster, title: title, year: year, imdbID: imdbID)

                    fetchedMovies.append(movie)

                }
                completionHandler(fetchedMovies)
            }

        }

    })

  }
}

First of all, what is a closure and what would happen if I don't use it in this functions?

Now, how can I test this function? I call it in my AppDelegate like:

print(MovieDAO.getMovies(imdbTitle: "arq"))

But the xcode returns an error saying that is missing a parameter in the call. So, can you explain this to me? I read about it but I'm a beginner and it's still confusing to me.

Oh, I would like to print an array with the searched title. I'm almost sure that my function is not returning that. How can I adapt the function to do that?

Just for better comprehension, the API gives this Json for the movie searched:

{
Response = True;
Search =     (
            {
        Poster = "https://images-na.ssl-images-amazon.com/images/M/MV5BMjAxODQ2MzkyMV5BMl5BanBnXkFtZTgwNjU3MTE5OTE@._V1_SX300.jpg";
        Title = ARQ;
        Type = movie;
        Year = 2016;
        imdbID = tt5640450;
    },
            {
        Poster = "N/A";
        Title = Arq;
        Type = movie;
        Year = 2011;
        imdbID = tt2141601;
    },
            {
        Poster = "N/A";
        Title = "A.R.Q.";
        Type = movie;
        Year = 2015;
        imdbID = tt3829612;
    }
);
totalResults = 3;
}

Update 1:

I did like the suggestion and called (on my AppDelegate, just for test and see if it getting what I want, in this case, a list of the movies that contains the "arq" on title) my function like this:

MovieDAO.getMovies(imdbTitle: "arq") {
        (movies: [Movie]) in
        // Do something with the movies
        print(movies)
    }

The return was this error: (lldb) error

What is wrong with this line that is in green?


Solution

  • The Problem

    The function you are trying to call has a method signature like:

    getMovies(imdbTitle: String, completionHandler: @escaping (([Movie]) -> ()))

    You are trying to call it with just the first parameter: imdbTitle. The error you are seeing is because you never pass in the completion handler- you are missing the last parameter.

    The Solution

    Change your call to include the completion block, like so:

    MovieDAO.getMovies(imdbTitle: "Title") {
      (movies: [Movie]) in
      // Do something with the movies
      print(movies)
    }