Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ghibli Movie APp #4

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

Fostahh
Copy link

@Fostahh Fostahh commented Oct 20, 2022

No description provided.

@Fostahh Fostahh force-pushed the second-task branch 4 times, most recently from e0a4404 to 3da7100 Compare October 20, 2022 09:04
Copy link
Contributor

@zmkhtr zmkhtr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Azri.

Comment on lines 27 to 32
guard let url = URL(string: "https://ghibliapi.herokuapp.com/films") else {
DispatchQueue.main.async {
completion(.failure("Bad URL"))
}
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jangan pake guard let buat unwrap URL disini, kenapa? karena klo salah disini itu developer mistake bukan codenya, jadi untuk mencegah hal tersebut lebih baik ini di force unwrap.

Suggested change
guard let url = URL(string: "https://ghibliapi.herokuapp.com/films") else {
DispatchQueue.main.async {
completion(.failure("Bad URL"))
}
return
}
let url = URL(string: "https://ghibliapi.herokuapp.com/films")!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mau nanya Bang. Semisalnya invalid URL, ini ga ngecrash Bang kalo di force unwrap?

Comment on lines 59 to 64
guard let url = URL(string: "https://ghibliapi.herokuapp.com/films/\(movieId)") else {
DispatchQueue.main.async {
completion(.failure("Bad URL"))
}
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sama ini juga kyk yg diatas

Suggested change
guard let url = URL(string: "https://ghibliapi.herokuapp.com/films/\(movieId)") else {
DispatchQueue.main.async {
completion(.failure("Bad URL"))
}
return
}
let url = URL(string: "https://ghibliapi.herokuapp.com/films/\(movieId)")!

DispatchQueue.global(qos: .background).async {
guard let data = data else {
DispatchQueue.main.async {
completion(.success(nil))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throw error disini jangan success kalau emang datanya gaada, completion aja dengan completion(.failure("Data not found"))

Comment on lines 66 to 87
URLSession.shared.dataTask(with: url) { (data, response, error) in
DispatchQueue.global(qos: .background).async {
guard let data = data else {
DispatchQueue.main.async {
completion(.success(nil))
}
return
}

do {
let result = try JSONDecoder().decode(MovieResponse.self, from: data)
let response = ObjectMapper().mapMovieResponseToMovieDomain(movieResponse: result)
DispatchQueue.main.async {
completion(.success(response))
}
} catch {
DispatchQueue.main.async {
completion(.failure("Failed to convert"))
}
}
}
}.resume()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dari pada manggil DispatchQueue.main.async banyak'' bisa lu ganti aja tuh yg di line 67 DispatchQueue.global(qos: .background).async jadi langsung pake yg DispatchQueue.main.async. Karena URLSession defaultnya udah di background thread

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mapping object di Main thread gamasalah Bang?

Comment on lines 31 to 34
guard let movieId = movieId else {
self.navigationController?.popViewController(animated: true)
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ini bakal jadi weird behavior klo lu movieId missing ngepaksa user balik ke controller sebelumnya, ini bakal dikira ada bug. ada baiknya kalau emang missing yang lu bikin layout errornya jangan di force kyk gini.

Comment on lines 80 to 117
isDownloadingImage(true, movieImageContainerView)
isDownloadingImage(true, movieBannerContainerView)

movieImageView.kf.setImage(
with: url,
placeholder: nil,
options: nil,
progressBlock: { [weak self] _, _ in
self?.isDownloadingImage(true, self?.movieImageContainerView)
},
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false, self?.movieImageContainerView)
case .failure(let error):
self?.isDownloadingImage(false, self?.movieImageContainerView)
print(error)
}
}
)

movieBannerImageView.kf.setImage(
with: urlPoster,
placeholder: nil,
options: nil,
progressBlock: { [weak self] _, _ in
self?.isDownloadingImage(true, self?.movieBannerContainerView)
},
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false, self?.movieBannerContainerView)
case .failure(let error):
self?.isDownloadingImage(false, self?.movieBannerContainerView)
print(error)
}
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ini sebenernya bisa lu rubah jadi satu fungsi tinggal dirubah parameter imageViewnya aja.

Suggested change
isDownloadingImage(true, movieImageContainerView)
isDownloadingImage(true, movieBannerContainerView)
movieImageView.kf.setImage(
with: url,
placeholder: nil,
options: nil,
progressBlock: { [weak self] _, _ in
self?.isDownloadingImage(true, self?.movieImageContainerView)
},
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false, self?.movieImageContainerView)
case .failure(let error):
self?.isDownloadingImage(false, self?.movieImageContainerView)
print(error)
}
}
)
movieBannerImageView.kf.setImage(
with: urlPoster,
placeholder: nil,
options: nil,
progressBlock: { [weak self] _, _ in
self?.isDownloadingImage(true, self?.movieBannerContainerView)
},
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false, self?.movieBannerContainerView)
case .failure(let error):
self?.isDownloadingImage(false, self?.movieBannerContainerView)
print(error)
}
}
)
private func loadImageUsingKingfisher(url: URL, urlPoster: URL) {
downloadImage(for : movieImageContainerView, with : url)
downloadImage(for : movieBannerImageView, with : urlPoster)
}
private func downloadImage(for imageView: UIImageView, with url: URL) {
isDownloadingImage(true, imageView)
imageView.kf.setImage(
with: url,
placeholder: nil,
options: nil,
progressBlock: { [weak self] _, _ in
self?.isDownloadingImage(true, imageView)
},
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false, imageView)
case .failure(let error):
self?.isDownloadingImage(false, imageView)
print(error)
}
}
)
}

Comment on lines 28 to 42
movieImageView.kf.setImage(
with: url,
placeholder: nil,
options: nil,
progressBlock: nil,
completionHandler: { [weak self] result in
switch result {
case .success(_):
self?.isDownloadingImage(false)
case .failure(let error):
self?.isDownloadingImage(false)
print(error)
}
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ini juga sama, klo lu ngerasa berulang bgt, bisa dibikin ImageLoader nya sendiri jadi tinggal manggil class itu

Comment on lines 50 to 64
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { action in
switch action.style {
case .default:
print("default")

case .cancel:
print("cancel")

case .destructive:
print("destructive")

default:
print("default")
}
}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Klo gaada action yg dihandle ga perlu diimplement switch case nya

Comment on lines 15 to 33
class DetailMovieViewModel {
private let movieNetworkModel : MovieNetworkModel

init(movieNetworkModel: MovieNetworkModel) {
self.movieNetworkModel = movieNetworkModel
}

func retrieveMovie(movieId: String, completion : @escaping (RetrievingDetailMovieState) -> ()) {
movieNetworkModel.getMovie(movieId: movieId) { result in
switch result {
case .success(let movie):
completion(.success(movie))
case .failure(let message):
completion(.failure(message))
}
}

}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Klo niat lu implement MVVM, lu gabisa bilang ini ViewModel, karena viewModel di MVVM itu punya binder/observer yang menjadi pembeda itu sama MVC. lu harus bikin binder/observernya terus di observer di view, instead of lu handle from escaping when calling retrieveMovie(..). jadi Klo MVVM gamake result dari Completion ini jadi ga perlu ada completion di function retrieveMovie(..).

Ini berlaku untuk semua ViewModel yang lu implementasikan Project ini

Suggested change
class DetailMovieViewModel {
private let movieNetworkModel : MovieNetworkModel
init(movieNetworkModel: MovieNetworkModel) {
self.movieNetworkModel = movieNetworkModel
}
func retrieveMovie(movieId: String, completion : @escaping (RetrievingDetailMovieState) -> ()) {
movieNetworkModel.getMovie(movieId: movieId) { result in
switch result {
case .success(let movie):
completion(.success(movie))
case .failure(let message):
completion(.failure(message))
}
}
}
}
class DetailMovieViewModel {
private let movieNetworkModel : MovieNetworkModel
private var resultsObserver : ((Movie) -> ()?) // nanti ini yg lu observer di Controllernya
private var errorObserver : ((String) -> ()?) // nanti ini yg lu observer di Controllernya
init(movieNetworkModel: MovieNetworkModel) {
self.movieNetworkModel = movieNetworkModel
}
func retrieveMovie(movieId: String) {
movieNetworkModel.getMovie(movieId: movieId) { result in
switch result {
case .success(let movie):
resultsObserver?(movie)
case .failure(let message):
errorObserver?(message)
}
}
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants