質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1066閲覧

APIレスポンスをUITableViewCellに各々表示するにあたり不明な点

Ytan

総合スコア39

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/07/27 09:55

前回の質問からの進展

前回思うように結果を受け取れたので
1.queryを入れ複数の情報に対応させました。
2.TextFieldを追加してTableViewで検索機能を追加。
3.TableViewCellを作成しnibに表示したい項目を追加。
4.新たにidをAPiから取得してdidselectを追加。

ソースコード

ViewController

1import UIKit 2import SafariServices 3 4class ViewController: UIViewController,UITextFieldDelegate { 5 6 @IBOutlet weak var movieTableView: UITableView! 7 @IBOutlet weak var field: UITextField! 8 9 var movies = [Movie]() 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 movieTableView.register(MovieTableViewCell.nib(), forCellReuseIdentifier: MovieTableViewCell.identifier) 14 15 movieTableView.delegate = self 16 movieTableView.dataSource = self 17 field.delegate = self 18 19 fechData() 20 } 21 22 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 23 fechData() 24 return true 25 } 26 27 func fechData(){ 28 29 field.resignFirstResponder() 30 31 guard let text = field.text, !text.isEmpty else { 32 return 33 } 34 35 let query = text.replacingOccurrences(of: " ", with: "%20") 36 let url = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) 37 38 movies.removeAll() 39 40 URLSession.shared.dataTask(with: URL(string: "https://api.themoviedb.org/3/search/movie?api_key=自分のAPI&language=ja&query=(query)&page=1")!, 41 completionHandler: {data, response, error in 42 43 guard let data = data else { 44 print(error?.localizedDescription ?? "Unknown error") 45 return 46 } 47 48 var result: MovieStruct? 49 do { 50 result = try JSONDecoder().decode(MovieStruct.self, from: data) 51 } 52 catch{ 53 print("JSON perse error") 54 } 55 56 guard let finalResult = result else{ 57 return 58 } 59 60 let newMovies = finalResult.results 61 self.movies.append(contentsOf: newMovies) 62 63 DispatchQueue.main.async { 64 self.movieTableView.reloadData() 65 } 66 }).resume() 67 } 68} 69 70extension ViewController:UITableViewDelegate,UITableViewDataSource{ 71 72 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 73 return movies.count 74 } 75 76 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 77 let cell = movieTableView.dequeueReusableCell(withIdentifier: MovieTableViewCell.identifier, for: indexPath) as! MovieTableViewCell 78 cell.configure(with: movies[indexPath.row]) 79 return cell 80 } 81 82 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 83 tableView.deselectRow(at: indexPath, animated: true) 84 let url = "https://www.themoviedb.org/movie/(movies[indexPath.row].id)?language=ja" 85 let vc = SFSafariViewController(url: URL(string: url)!) 86 present(vc, animated: true) 87 } 88} 89 90struct MovieStruct:Codable { 91 let results: [Movie] 92} 93 94struct Movie: Codable { 95 let title: String 96 let release_date:String? 97 let poster_path:String? 98 let id:Int? 99}

TableViewCell

MovieTableViewCell

1import UIKit 2 3class MovieTableViewCell: UITableViewCell { 4 5 @IBOutlet var movieTitleLabel: UILabel! 6 @IBOutlet var movieReleaseDateLabel: UILabel! 7 @IBOutlet var moviePosterImageView: UIImageView! 8 9 override func awakeFromNib() { 10 super.awakeFromNib() 11 // Initialization code 12 } 13 14 override func setSelected(_ selected: Bool, animated: Bool) { 15 super.setSelected(selected, animated: animated) 16 17 } 18 19 static let identifier = "MovieTableViewCell" 20 21 static func nib() -> UINib{ 22 return UINib(nibName: "MovieTableViewCell", bundle: nil) 23 } 24 25 func configure(with model:Movie){ 26 self.movieTitleLabel.text = model.title 27 self.movieReleaseDateLabel.text = model.release_date 28 let url = model.poster_path 29 if let data = try? Data(contentsOf: URL(string: url!)!){ 30 self.moviePosterImageView.image = UIImage(data: data) 31 } 32 } 33} 34

不明点&エラー

1.検索Hitにばらつきがあり、urlにnillが入ってしまう。

例えばstarと入力するとSTARWARSの情報が出るのですが
titanicと入力するとconfigureのところで

Fatal error: Unexpectedly found nil while unwrapping an Optional value

となりurlにnillが入っています。

2.posterが表示されない
上記の検索Hitした、していないにかかわらず
Hitした場合MovieTableViewCellで設定したmoviePosterImageViewが何も表示されずに真っ白です。
titleとrelease_dateは表示されるのでposter_pathのみ受け取れていないのかどこかでnilを設定してしまわれているのだと思います。

3.日本語対応ができない
以前APIの日本語を受け取るためには

let url = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

で日本語対応できると習ったのですがURLSessionのところで

Fatal error: Unexpectedly found nil while unwrapping an Optional value

と出てしまいます。

4.didselectで思うようなサイトに飛べない。

let url = "https://www.themoviedb.org/movie/(movies[indexPath.row].id)?language=ja" let vc = SFSafariViewController(url: URL(string: url)!) present(vc, animated: true)

このようにIMDBの映画情報詳細ページに飛びたいのですが
IMDBのHPサイトには飛ぶのですが探しているページは見つかりませんと出ます。

STARWARS 最後のジェダイの詳細URL https://www.themoviedb.org/movie/181808-star-wars-the-last-jedi?language=ja ドラえもん 宝島 //https://www.themoviedb.org/movie/495925?language=ja

上記のように検索URLにばらつきがあるので

let url = "https://www.themoviedb.org/movie/(movies[indexPath.row].id)?language=ja"

上記だとidのみを設定しているのでTitileも考慮して設定しなければなりませんか?
質問、コード等が多くなってしまい大変申し訳ありません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

1.検索Hitにばらつきがあり、urlにnillが入ってしまう。
2.posterが表示されない

前回指摘しましたが、model.poster_pathnil の場合があります。
映画によってはポスター情報(画像URL)が存在しない映画があるようで、そのような場合には nil が戻ってきます。

「titanic」で検索した場合、多くの映画はポスターがあるのですが、「titanic 2000」はポスターがないため、セルを作成している途中でエラーとなってしまいます。

また、model.poster_pathにはベース URL(という表現が正しいかわかりませんが)がなく、画像名しか入っていないため、ベース URL を追加する必要があります。

  • [https://developers.themoviedb.org/3/getting-started/images

](https://developers.themoviedb.org/3/getting-started/images)

これらをまとめて修正すると

Swift

1 func configure(with model:Movie){ 2 self.movieTitleLabel.text = model.title 3 self.movieReleaseDateLabel.text = model.release_date 4 // poster_path に URL を追加する。 5 // ちなみに、posther_path が nil の場合には無視 6 if let poster_path = model.poster_path { 7 let url = "https://image.tmdb.org/t/p/w500/" + poster_path 8 if let data = try? Data(contentsOf: URL(string: url)!){ 9 self.moviePosterImageView.image = UIImage(data: data) 10 } 11 } else { 12 // 該当するポスターがない場合 13 // titanic 2000 など 14 moviePosterImageView.image = nil 15 } 16 }

のような感じになります。

Cell は使い回しされるため、もし画像データがない場合には、moviePosterImageView.imagenil を入れたり、あるいは「ポスターがない」に相当する画像を表示するようにした方がよいかもしれません。

3.日本語対応ができない

Swift

1let url = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

addingPercentEncoding(withAllowedCharaters:)の戻り値はオプショナル型なので、そのことを念頭に置く必要があります。

Return Value

Returns the encoded string, or nil if the transformation is not possible.

簡単に修正すると

Swift

1 //let query = text.replacingOccurrences(of: " ", with: "%20") 2 //let url = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) 3 4 guard let query = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { 5 // 変換できなかった時の処理 6 print("パーセントエンコーディング失敗") 7 return 8 }

このような感じで一応日本語でも検索できるようになります。

4.didselectで思うようなサイトに飛べない。

これはご自身で API リファレンスを読み込んでいただき、詳細情報の URL を取得できるような方法を調べていただくしかないかと思います。

少なくとも今回検索している JSON にはそのような情報は入っていないように思えます。

投稿2020/07/27 19:34

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ytan

2020/07/31 13:22

返信が遅くなってしまい申し訳ありません。 APIのリファレンスにそれぞれ使い方があるのですね、二つとも問題なく稼働して思うようなアプリにようやく仕上がりました。誠にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問