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

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

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

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

Swift

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

Q&A

解決済

1回答

2060閲覧

Tableviewのスクロールが重い

dragon_seven

総合スコア7

Xcode

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

Swift

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

0グッド

0クリップ

投稿2019/08/29 03:08

編集2019/09/01 13:55

前提・実現したいこと

Xcodeで開発している最新の映画を確認できるiOSアプリで、外部のデーターベースからAPIを使ってListviewに表示させてスムーズにスクロールさせたい。

発生している問題・エラーメッセージ

APIを使ってListviewに表示できるところまでは出来ましたが、実機にビルドしてスクロールするとカクカクして重い感じがあります。

試したこと

Macのキャッシュクリアなども試しましたが効果が見られませんでした。

コード

Swift

1static func searchMovie(count : Int) { 2 //リクエストURLの組み立て 3 guard let req_url = URL(string: "https://api.themoviedb.org/3/movie/upcoming?page=(count)&language=jp&api_key=45cfffebd76a148b4c8907aed12b6eae" 4 ) else { 5 return 6 } 7 //リクエストに必要な情報を生成 8 let req = URLRequest(url: req_url) 9 10 //リクエストをタスクとして登録 11 let task = URLSession.shared.dataTask(with: req, completionHandler: { 12 (data , response , error) in 13 do { 14 // JSON Decoderのインスタンス取得 15 let decoder = JSONDecoder() 16 // 受け取ったJSONデータを解析して格納 17 let json = try decoder.decode(ResultJson.self , from: data!) 18 //print(json) 19 // 映画の情報が取得できているか確認 20 if let resultList = json.results { 21 // 取得している映画の情報の数だけ処理する 22 for results in resultList { 23 // 映画のタイトル、公開日、ポスターのデータがあるか確認 24 if let original_title = results.original_title , var release_date = results.release_date , var 25 poster_path = results.poster_path { 26 // 公開日の”-”の文字が邪魔なので削除 27 if let range = release_date.range(of:"-") { 28 release_date.removeSubrange(range) 29 if let range = release_date.range(of:"-") { 30 release_date.removeSubrange(range) 31 } 32 } 33 // 画像ファイルの”/”が邪魔なので削除 34 if let range = poster_path.range(of:"/") { 35 poster_path.removeSubrange(range) 36 } 37 // それぞれの配列に入れる 38 movieTitleList.append(original_title) 39 moviePosterPathList.append(URL(string: "https://image.tmdb.org/t/p/w500/(poster_path)")!) 40 41 // 公開日は後でソートしたいのでInt型に変換して格納 42 movieReleaseDateList.append(Int(release_date)!) 43 // 日付の配列にも公開日を格納 44 DatemovieReleaseDateList.append(ViewController.dateFormater.date(from: release_date)!) 45 46 // print(date?.description ?? "nil") 47 // 公開日に合わせてタイトル、ポスターの画像を降順にソート 48 for _ in 0..<movieReleaseDateList.count-1 { 49 for j in 0..<movieReleaseDateList.count-1 { 50 if(movieReleaseDateList[j] > movieReleaseDateList[j+1]){ 51 let t = movieReleaseDateList[j] 52 movieReleaseDateList[j] = movieReleaseDateList[j+1] 53 movieReleaseDateList[j+1] = t 54 55 let k = movieTitleList[j] 56 movieTitleList[j] = movieTitleList[j+1] 57 movieTitleList[j+1] = k 58 59 let l = moviePosterPathList[j] 60 moviePosterPathList[j] = moviePosterPathList[j+1] 61 moviePosterPathList[j+1] = l 62 63 let p = DatemovieReleaseDateList[j] 64 DatemovieReleaseDateList[j] = DatemovieReleaseDateList[j+1] 65 DatemovieReleaseDateList[j+1] = p 66 } 67 } 68 } 69 } 70 } 71 } 72 semaphore.signal() 73 } catch { 74 print("エラー発生") 75 } 76 }) 77 //ダウンロード開始 78 task.resume() 79 }

補足情報(FW/ツールのバージョンなど)

・Xcode 10.2.1
・Swift 5.0.1

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

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

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

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

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

hayabusabusash

2019/08/29 03:25 編集

ListViewというのはTableViewですか? また、可能ならコードを貼っていただけないでしょうか?
dragon_seven

2019/08/30 00:53

ListviewではなくTableviewですね コードを追加しておきます
hayabusabusash

2019/08/30 01:06

semaphoreってDispatchSemaphoreを使ってますか? もしそうならこれが原因なのではないでしょうか? あとTableViewのコードも貼っていただけるともう少し詳しく回答することができるかもしれません。
dragon_seven

2019/08/30 01:33

DispatchSemaphoreを使っていました これが原因だとしたら代替できる機能を教えてくれませんか? Tableviewのコードとは宣言しているところや詳細の設定をしているところでしょうか?
hayabusabusash

2019/08/30 01:40

semaphoreの代替の部分少し長そうなので回答に書きます。 そうです!TableViewの部分も念のためよろしくお願いいたします。
dragon_seven

2019/08/30 02:02

`// 一つのセクションに何個のセルが入るのか func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return ViewController.koukaibiList[section].count } // レイアウトをカスタマイズしたcustomCellClassをtable view cellに適応している func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! customCellClass ViewController.sectionNum = indexPath.section cell.cellDisplayControl(indexPath: indexPath) cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator return cell } // セクションの数をを決める func numberOfSections(in tableView: UITableView) -> Int { return ViewController.sectionName.count } // セクションのタイトル表示 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return ViewController.dateFormater2.string(from: ViewController.sectionName[section] as Date) } // セクションの高さを決める func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 40 } // tableViewの設定 func createTable() { self.tableView.delegate = self self.tableView.dataSource = self // cellの高さ設定 tableView.rowHeight = 110 // sectionの色の設定 tableView.backgroundColor = UIColor(red:1.1,green:1.1,blue:1.1,alpha:0.9) } // tableViewのcell選択時のアクション func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // セルの選択を解除 tableView.deselectRow(at: indexPath, animated: true) // 別の画面に遷移 performSegue(withIdentifier: "tomovieDetails", sender: nil) // タップされたセルのIndexPathを表示 //print("section: \(indexPath.section), row: \(indexPath.row)") ViewController.judge = 0 ViewController.section = indexPath.section ViewController.row = indexPath.row }`
dragon_seven

2019/08/30 02:04

teratail初心者でわからないのですが回答にコードを添付する時ってこのやり方であってますか? これがTableviewの詳細設定をしているところですね
hayabusabusash

2019/08/30 02:15

TableViewのコードありがとうございます! 一応代替案について回答しましたのでご確認ください。
guest

回答1

0

ベストアンサー

DispatchSemaphoreを使っていらっしゃるようですが、
多分このままだとメインスレッドがブロックされてしまってTableViewの描画などに影響が出ているんじゃないかなと思います。UIの描画はメインスレッドで行われるので。(参考)

なのでこの場合DispatchSemaphoreがメインスレッドをブロックしないように工夫するのか、
もしくは関数の引数にクロージャを持たせてそこに処理の結果を渡し、その中でUIの描画をするようにすればいいと思います。

動作未確認なので申し訳ないですが、
以下のようにしてみるのはどうでしょうか?

Swift

1// resultの部分は任意のものに変えてください 2func searchMovie(count : Int, completion: @escaping ((_ result: /*任意の結果(オプショナル)*/, _ error: Error?) -> Void)) { 3 //リクエストURLの組み立て 4 guard let req_url = URL(string: "https://api.themoviedb.org/3/movie/upcoming?page=(count)&language=jp&api_key=45cfffebd76a148b4c8907aed12b6eae" 5 ) else { 6 return 7 } 8 //リクエストに必要な情報を生成 9 let req = URLRequest(url: req_url) 10 11 //リクエストをタスクとして登録 12 let task = URLSession.shared.dataTask(with: req, completionHandler: { (data , response , error) in 13 14 // 省略します 15 16 do { 17 // 省略します 18 completion(result, nil) 19 } catch let error { 20 // Jsonのデコードエラーが発生した場合 21 completion(nil, error) 22 } 23 } 24 25}

使うときには以下のようにします。

Swift

1searchMovie(count: 10, completion: { (result, error) in 2 guard let error = error else { 3 // エラーが発生したとき 4 return 5 } 6 if let result = result { 7 DispatchQueue.main.async { 8 // TableViewの更新の処理 9 } 10 } 11})

投稿2019/08/30 02:06

hayabusabusash

総合スコア767

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

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

dragon_seven

2019/08/30 05:41

問題なくできました ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問