使用 AlamofireObjectMapper/ObjectMapper 从数组 objects 获取值 (swift - iOS)
Get value from array objects with AlamofireObjectMapper/ObjectMapper (swift - iOS)
我是这个映射器的新手,太困惑了。我有一个 API 请求,给定一个标题,API return 这个:
{
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;
}
所以我为此结果创建了一个可映射的class:
class SearchResponse: Mappable {
var isSuccess : String?
var searchArray: [Movie]?
var searchCount: String?
required init?(map: Map) {
}
func mapping(map: Map) {
isSuccess <- map["Response"]
searchArray <- map["Search"]
searchCount <- map["totalResults"]
}
}
class Movie: Mappable {
var posterURL : String?
var title : String?
var runtime : String?
var director : String?
var actors : String?
var genre : String?
var plot : String?
var production : String?
var year : String?
var imdbID : String?
var imdbRating : String?
required init?(map: Map) {
}
func mapping(map: Map) {
posterURL <- map["Poster"]
title <- map["Title"]
runtime <- map["Runtime"]
director <- map["Director"]
actors <- map["Actors"]
genre <- map["Genre"]
plot <- map["Plot"]
production <- map["Production"]
year <- map["Year"]
imdbID <- map["imdbID"]
imdbRating <- map["imdbRating"]
}
}
Question: I mapped this movie class like this, but for the search by title I'll only have 4 of this attributes. But for the next search I'll need all of them. Is that right? Or should I create two separate classes to deal with each kind of response?
好的!我正在我的 SearchTableViewController 上显示此搜索的结果。现在我想显示这部电影的更多细节(之前响应中 "Search" 数组的任何电影)。为此,API 提供了另一种搜索类型,即按 imdbID 搜索。因此,我在我的 SearchTableViewController 上创建了一个 segue 以获取此 ID 并传递给我的 MovieViewController(将显示这些详细信息的视图):
let searchSegue = "segueFromSearch"
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let searchIndex = tableView.indexPathForSelectedRow?.row
let movie = movies?[searchIndex!]
let selectedImdbID = movie?.imdbID
print("|Table View Controler| Segue. IMDB_ID: \(String(describing: selectedImdbID))")
if segue.identifier == searchSegue {
if let destination = segue.destination as? MovieViewController {
destination.imdbID = selectedImdbID!
print("|Table View Controler| Inside of if let. Debug print: I get til here. imdbID = \(selectedImdbID!)")
}
}
}
我对这个 API 请求的函数是:
//The movieSearched variable is the text typed on my searchBar
let URL = "https://www.omdbapi.com/?s=\(movieSearched)&type=movie"
Alamofire.request(URL).responseObject{ (response: DataResponse<SearchResponse>) in
print("response is: \(response)")
switch response.result {
case .success(let value):
let searchResponse = value
self.movies = (searchResponse.searchArray)
self.searchTableView.reloadData()
case .failure(let error):
let alert = UIAlertController(title: "Error", message: "Error 4xx / 5xx: \(error)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
好的,鉴于我所拥有的这个概述,让我们谈谈我的问题...
当我按 ID 搜索时,Json 响应是:
{
Actors = "Robbie Amell, Rachael Taylor, Shaun Benson, Gray Powell";
Awards = "N/A";
BoxOffice = "N/A";
Country = "USA, Canada";
DVD = "16 Sep 2016";
Director = "Tony Elliott";
Genre = "Sci-Fi, Thriller";
Language = English;
Metascore = "N/A";
Plot = "Trapped in a lab and stuck in a time loop, a disoriented couple fends off masked raiders while harboring a new energy source that could save humanity.";
Poster = "https://images-na.ssl-images-amazon.com/images/M/MV5BMjAxODQ2MzkyMV5BMl5BanBnXkFtZTgwNjU3MTE5OTE@._V1_SX300.jpg";
Production = Netflix;
Rated = "N/A";
Ratings = (
{
Source = "Internet Movie Database";
Value = "6.4/10";
},
{
Source = "Rotten Tomatoes";
Value = "60%";
}
);
Released = "16 Sep 2016";
Response = True;
Runtime = "88 min";
Title = ARQ;
Type = movie;
Website = "N/A";
Writer = "Tony Elliott";
Year = 2016;
imdbID = tt5640450;
imdbRating = "6.4";
imdbVotes = "17,481";
}
我的问题
我通过 ID 发出了这个 alamofire 搜索请求:
func getMovieById() {
let URL = "https://www.omdbapi.com/?i=\(String(describing: imdbID!)))"
Alamofire.request(URL).responseObject{ (response: DataResponse<SearchResponse>) in
print("|MovieController| Response is: \(response)")
let Result = response.result.value
print("Result for search by id: \(String(describing: Result!.searchArray))")
// Have to get the values here, right?
}
}
显然,我在这里没有得到我想要的数据。所以...
Questions:
- 如何使用可映射的 classes 获取 Json["Search"] 的值?
- 我必须更改现有的 classes 吗?如果是,如何以及为什么?
层层叠叠看得我眼花缭乱。另外,我是 swift 的初学者,我是第一次使用这个 ObjectMapper。抱歉这里有这么多代码,但我想我必须解释一下我的场景。
您必须使用 属性 的正确 数据类型 映射每个 属性。您的响应中的对象之一包含 布尔值 值(例如 "Response"),但您将其声明为字符串。我们必须准确匹配 属性 的数据类型,否则对象将为 nil 并且不会被映射。
此外 按 ID 搜索 响应与您的映射器不匹配 class。
let Result = response.result.value
是错误的。 response.result.value
会给你 SearchResponse
对象。
底线
你必须先把映射部分弄好。任何不匹配的类型都不会被映射。使用响应对象将为您提供包含所有映射的整个对象,而不是 JSON 显然。所以应该是:let movie = response.result.value
。然后你访问电影的属性,比如 ex. movie.actors
我是这个映射器的新手,太困惑了。我有一个 API 请求,给定一个标题,API return 这个:
{
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;
}
所以我为此结果创建了一个可映射的class:
class SearchResponse: Mappable {
var isSuccess : String?
var searchArray: [Movie]?
var searchCount: String?
required init?(map: Map) {
}
func mapping(map: Map) {
isSuccess <- map["Response"]
searchArray <- map["Search"]
searchCount <- map["totalResults"]
}
}
class Movie: Mappable {
var posterURL : String?
var title : String?
var runtime : String?
var director : String?
var actors : String?
var genre : String?
var plot : String?
var production : String?
var year : String?
var imdbID : String?
var imdbRating : String?
required init?(map: Map) {
}
func mapping(map: Map) {
posterURL <- map["Poster"]
title <- map["Title"]
runtime <- map["Runtime"]
director <- map["Director"]
actors <- map["Actors"]
genre <- map["Genre"]
plot <- map["Plot"]
production <- map["Production"]
year <- map["Year"]
imdbID <- map["imdbID"]
imdbRating <- map["imdbRating"]
}
}
Question: I mapped this movie class like this, but for the search by title I'll only have 4 of this attributes. But for the next search I'll need all of them. Is that right? Or should I create two separate classes to deal with each kind of response?
好的!我正在我的 SearchTableViewController 上显示此搜索的结果。现在我想显示这部电影的更多细节(之前响应中 "Search" 数组的任何电影)。为此,API 提供了另一种搜索类型,即按 imdbID 搜索。因此,我在我的 SearchTableViewController 上创建了一个 segue 以获取此 ID 并传递给我的 MovieViewController(将显示这些详细信息的视图):
let searchSegue = "segueFromSearch"
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let searchIndex = tableView.indexPathForSelectedRow?.row
let movie = movies?[searchIndex!]
let selectedImdbID = movie?.imdbID
print("|Table View Controler| Segue. IMDB_ID: \(String(describing: selectedImdbID))")
if segue.identifier == searchSegue {
if let destination = segue.destination as? MovieViewController {
destination.imdbID = selectedImdbID!
print("|Table View Controler| Inside of if let. Debug print: I get til here. imdbID = \(selectedImdbID!)")
}
}
}
我对这个 API 请求的函数是:
//The movieSearched variable is the text typed on my searchBar
let URL = "https://www.omdbapi.com/?s=\(movieSearched)&type=movie"
Alamofire.request(URL).responseObject{ (response: DataResponse<SearchResponse>) in
print("response is: \(response)")
switch response.result {
case .success(let value):
let searchResponse = value
self.movies = (searchResponse.searchArray)
self.searchTableView.reloadData()
case .failure(let error):
let alert = UIAlertController(title: "Error", message: "Error 4xx / 5xx: \(error)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
好的,鉴于我所拥有的这个概述,让我们谈谈我的问题...
当我按 ID 搜索时,Json 响应是:
{
Actors = "Robbie Amell, Rachael Taylor, Shaun Benson, Gray Powell";
Awards = "N/A";
BoxOffice = "N/A";
Country = "USA, Canada";
DVD = "16 Sep 2016";
Director = "Tony Elliott";
Genre = "Sci-Fi, Thriller";
Language = English;
Metascore = "N/A";
Plot = "Trapped in a lab and stuck in a time loop, a disoriented couple fends off masked raiders while harboring a new energy source that could save humanity.";
Poster = "https://images-na.ssl-images-amazon.com/images/M/MV5BMjAxODQ2MzkyMV5BMl5BanBnXkFtZTgwNjU3MTE5OTE@._V1_SX300.jpg";
Production = Netflix;
Rated = "N/A";
Ratings = (
{
Source = "Internet Movie Database";
Value = "6.4/10";
},
{
Source = "Rotten Tomatoes";
Value = "60%";
}
);
Released = "16 Sep 2016";
Response = True;
Runtime = "88 min";
Title = ARQ;
Type = movie;
Website = "N/A";
Writer = "Tony Elliott";
Year = 2016;
imdbID = tt5640450;
imdbRating = "6.4";
imdbVotes = "17,481";
}
我的问题
我通过 ID 发出了这个 alamofire 搜索请求:
func getMovieById() {
let URL = "https://www.omdbapi.com/?i=\(String(describing: imdbID!)))"
Alamofire.request(URL).responseObject{ (response: DataResponse<SearchResponse>) in
print("|MovieController| Response is: \(response)")
let Result = response.result.value
print("Result for search by id: \(String(describing: Result!.searchArray))")
// Have to get the values here, right?
}
}
显然,我在这里没有得到我想要的数据。所以...
Questions:
- 如何使用可映射的 classes 获取 Json["Search"] 的值?
- 我必须更改现有的 classes 吗?如果是,如何以及为什么?
层层叠叠看得我眼花缭乱。另外,我是 swift 的初学者,我是第一次使用这个 ObjectMapper。抱歉这里有这么多代码,但我想我必须解释一下我的场景。
您必须使用 属性 的正确 数据类型 映射每个 属性。您的响应中的对象之一包含 布尔值 值(例如 "Response"),但您将其声明为字符串。我们必须准确匹配 属性 的数据类型,否则对象将为 nil 并且不会被映射。
此外 按 ID 搜索 响应与您的映射器不匹配 class。
let Result = response.result.value
是错误的。 response.result.value
会给你 SearchResponse
对象。
底线
你必须先把映射部分弄好。任何不匹配的类型都不会被映射。使用响应对象将为您提供包含所有映射的整个对象,而不是 JSON 显然。所以应该是:let movie = response.result.value
。然后你访问电影的属性,比如 ex. movie.actors