这个功能对吗?使用闭包调用函数(swift - iOS)

时间:2017-04-19 06:17:16

标签: ios json swift api alamofire

问题

我必须在API上搜索一部电影,并在我的桌面视图中返回搜索到的电影。

语言

Swift 3 - xcode 8

从API

获取Json的函数
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)
    }
}
//------------------------------------------------

这个名为Movie的类(将在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 }

  }
}

然后,我的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)
            }

        }

    })

  }
}

首先,什么是闭包,如果我不在这个函数中使用它会发生什么?

现在,我该如何测试这个功能?我在我的AppDelegate中称它为:

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

但是xcode返回一个错误,说明在调用中缺少一个参数。那么,你能解释一下吗?我读到了它,但我是一个初学者,它仍然让我感到困惑。

哦,我想用搜索过的标题打印一个数组。我几乎可以肯定我的功能没有返回。我该如何调整功能呢?

为了更好地理解,API为搜索的电影提供了这个Json:

{
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;
}

更新1:

我确实喜欢这个建议并且调用了(在我的AppDelegate上,只是为了测试并看看它是否得到我想要的,在这种情况下,包含标题上的“arq”的电影列表)我的功能如下:

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

返回是这个错误: (lldb) error

这条绿线有什么问题?

2 个答案:

答案 0 :(得分:1)

问题

您尝试调用的函数具有以下方法签名:

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

您尝试仅使用第一个参数调用它:imdbTitle。您看到的错误是因为您从未传递完成处理程序 - 您缺少最后一个参数。

解决方案

更改您的通话以包含完成功能块,如下所示:

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

答案 1 :(得分:0)

将闭包想象成一堆你想要运行的代码,然后保存为一个变量,然后传递给函数。

这就是你在MoviesDAO中的GetMovies函数调用中所做的事情

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

completionHandler参数需要一个代码块,该代码块接受一个Movie对象数组并对其执行某些操作。 (可能在您的情况下打印)。

因为,正在发生的事情是你在问一些API(IMDB),“嘿,我想让你给我一堆名为'arg'的电影”。 IMDB无法立即向您提供该信息,并且您不希望程序的其余部分等待,因此您的GetMovies函数调用要求在获取电影对象数组后运行某些代码。

completionHandler(fetchedMovies)

您已经将您的功能参数命名为有点令人困惑,这可能对您正在阅读的内容没有帮助。你有一些与SearchMoviesOnJSON函数的completionHandler冲突的时髦名字。所以我要重命名你的getMovies函数,但只留下SearchMoviesOnJSON。

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

所以不要打电话

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

你应该做的是定义一个getMovies函数最后调用的闭包(一块代码)。

MovieDAO.getMovies(imdbTitle: "arg", handlerForMovieArray: {
    MoviesList in //<-- This is your input. 
    //Your array of movies that is being passed by the call to "handlerForMovieArray"

    //Do some fancy code stuff here. Probably want to loop over MoviesList and print the values you want
})

我希望这有帮助!如果您有更多问题,请联系。