First of all, I'm a beginner and I'm trying to build an app that search a movie on OMDB API and return a list of movie (when searched by title) and return an specific movie when searched by imdbID. I have to make two types of request for the api, because the result for search by id have the same atributes that the search by title have but with more details (need this to show a view with a selected movie from this list of results).
So, it was recommended to me (here) to use AlamofireObjectMapper/ObjectMapper to do it better. I did mapped like this:
import Foundation
import AlamofireObjectMapper
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"]
}
}
I would like to do something like this:
//Get movie by title - the user will enter the title on a searchbar
let url = "https:www.omdbapi.com/?s=(imdbTitle)"
func getMoviesByTitle (imdbTitle: String) {
/* The Alamofire function using ObjectMapper goes here */
switch
case .success():
/*Something*/
completionHandler(???)
case .failure():
/*Something*/
completionHandler(???)
}
//Get movie by ID
let url = "https:www.omdbapi.com/?i=(imdbID)"
func getMovieByID(imdbID: String) {
/* The Alamofire function using ObjectMapper goes here */
if let response {
completioHandler(???)
} /* Something like this? */
}
I need some guide. When I search a movie by Title it returns an JSON with Response, Search("array" of movies) and totalResults. In this case, my Movie class only have four of those mapping attributes (Poster, Title, Year, imdbID).
- Is this mapping right?
- How can I make those requests for each case? I mean, what should I return? (Because my getMovie functions need a completionHandler, right?)
EDIT
So, I've tried this on my SearchTableViewController:
import UIKit
import Alamofire
import AlamofireObjectMapper
import ObjectMapper
import Kingfisher
class SearchTableViewController: UITableViewController, UISearchResultsUpdating {
@IBOutlet var searchTableView: UITableView!
@IBAction func showResults(_ sender: Any) {
let searchController = UISearchController(searchResultsController: nil)
self.present(searchController, animated: true, completion: nil)
searchController.searchBar.barTintColor = self.searchTableView.backgroundColor!
searchController.searchResultsUpdater = self
}
var movies = [Movie]()
override func viewDidLoad() {
super.viewDidLoad()
searchTableView.dataSource = self
searchTableView.delegate = self
}
func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
if searchText == "" {
return
}
else {
let movieSearched: String = searchText.replacingOccurrences(of: " ", with: "_")
// MARK: Alamofire Get by Title
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)
}
}
DispatchQueue.main.async {
let spinnerActivity = MBProgressHUD.showAdded(to: self.view, animated: true)
spinnerActivity.label.text = "Loading";
spinnerActivity.detailsLabel.text = "Searching movie..."
spinnerActivity.isUserInteractionEnabled = false;
}
DispatchQueue.main.async {
MBProgressHUD.hide(for: self.view, animated: true)
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return movies.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCellIdentifier", for: indexPath) as! SearchTableViewCell
let movie = movies[indexPath.row]
let imgStg: String = movie.posterURL!
let imgURL: URL? = URL(string: imgStg)
let imgSrc = ImageResource(downloadURL: imgURL!, cacheKey: imgStg)
cell.titleLabel.text = movie.title
cell.yearLabel.text = movie.year
cell.posterImageView.layer.cornerRadius = cell.posterImageView.frame.size.width/2
cell.posterImageView.clipsToBounds = true
//image cache with KingFisher
cell.posterImageView.kf.setImage(with: imgSrc)
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
The search is working, until I type 4 characters... Until the 3th character typed, the table view show in real time the results, but when I type the 4th, the app crashs. The error is this:
See Question&Answers more detail:
os