Hi!!! I have this problem, I have an app with an API, I bring all the popular movies, and I have a search bar where I bring all the movies that are written on the search bar... The thing is that I have to make a like button and also save de data of the liked ones with user defaults, also I have to have two sections in my tableview, the first one shows the liked ones and the other section the other films. How can I implement this? Thank you in advance!!!!
How to filter data from an api, and how to use userdefaults to load and save data?
Are you storing the movies themselves or just metadata about them? Also, which UI framework are you using to show your content?
I'm using UIKit, Swift, just that is what I can use. And I'm making this: but I do not know if it is ok because I do not know how to implement it correctly my network is this :
import UIKit
import Foundation
class NetworkManager {
// MARK: - ENUM NETWORKCONSTANTS
enum NetworkConstants {
static let urlString = "https://api.themoviedb.org/3/movie/popular?api_key=669056d94db324f563f195952deaede4&language=en-US&page=1"
static let imageUrlFirstPart = "https://image.tmdb.org/t/p/w500"
}
// MARK: - GETMOVIEDATA - URL AND PARSE FUNC
func getMovieData(completion: @escaping ([MovieData]) -> Void) {
guard let url = URL(string: NetworkConstants.urlString) else {
completion([])
return
}
let session = URLSession.shared
let dataTask = session.dataTask(with: url) { (data, response, error) in
guard error == nil, let dataResponse = response as? HTTPURLResponse, dataResponse.statusCode == 200, let data = data else {
completion([])
return
}
do {
let saveDataKey = "id"
var moviesData = [ResultsMovieModel]()
let decoder = JSONDecoder()
let movie = try decoder.decode(ResultsMovieModel.self, from: data)
let defaults = UserDefaults.standard
if let readData = defaults.data(forKey: saveDataKey) {
do {
moviesData = try decoder.decode([ResultsMovieModel].self, from: readData)
} catch {
print(error)
}
}
moviesData.append(movie)
let saveData = try JSONEncoder().encode(moviesData)
defaults.setValue(saveData, forKey: saveDataKey)
completion(movie.results)
} catch {
print(error)
}
}
dataTask.resume()
// let dataTask = session.dataTask(with: url) { (data, response, error) in
// guard error == nil, let dataResponse = response as? HTTPURLResponse,
// dataResponse.statusCode == 200, let data = data else {
// completion([])
// return
// }
// guard let parsedData = try? decoder.decode(ResultsMovieModel.self, from: data) else {
// completion([])
// return
// }
// if let saveDataUD = UserDefaults.standard.data(forKey: saveDataKey) {
// do {
// moviesData = try decoder.decode([ResultsMovieModel].self, from: saveDataUD)
// } catch {
// print(error)
// }
// }
// moviesData.append(parsedData)
// let saveData = try JSONEncoder().encode(moviesData)
// completion(parsedData.results)
// }
// dataTask.resume()
}
// MARK: - LOADMOVIEIMAGE FUNC
func loadMovieImage(backdropPath: String, completion: @escaping (UIImage) -> Void) {
let imageUrl = NetworkConstants.imageUrlFirstPart + backdropPath
guard let url = URL(string: imageUrl) else {
completion(UIImage(named: "artwork-source") ?? UIImage())
return
}
do {
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, error in
guard let dataResponse = data, let image = UIImage(data: dataResponse) else {
return
}
completion(image)
}
task.resume()
}
// let imageUrl = NetworkConstants.imageUrlFirstPart + backdropPath
// guard let url = URL(string: imageUrl) else {
// completion(UIImage(named: "artwork-source") ?? UIImage())
// return
// }
// let session = URLSession.shared
// let task = session.dataTask(with: url) { data, response, error in
// guard let dataResponse = data, let image = UIImage(data: dataResponse) else {
// completion(UIImage(named: "artwork-source") ?? UIImage())
// return
// }
// completion(image)
// }
// task.resume()
// }
}
}
I would recommend using Core Data instead of UserDefaults, since UserDefaults is designed for smaller scale things like device settings for an app for example. Core Data can easily handle the movie metadata. As for the thumbnail, you can store that too but its a little more complicated. I'm not entirely sure how to do it off the top of my head, but there should be a way to store it.
In terms of integrating Core Data with your user interface, you can use the NSFetchedResultsController to connect your UI where you would use the values from the fetched results controller to return as part of the UIKit implementation.
I would also recommend that you use Swift's new concurrency support if you're project has an iOS/iPadOS development target of iOS/iPadOS 15.0 or later. It'll make it more difficult to make mistakes such as leaving the caller of your methods hanging by not calling the completion handler by accident.