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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

Q&A

解決済

1回答

2657閲覧

ボタンをタップしたときに別のViewControllerのTableViewをリロードしたい

unagimochimochi

総合スコア7

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

0グッド

0クリップ

投稿2020/08/31 07:02

前提・実現したいこと

MapViewControllerのオレンジ色のお気に入りボタンをタップすると、FavViewControllerのTableViewに場所の名前や住所が追加される、といった機能を実装したいです。

↓MapViewController
MapViewController

↓FavViewController
FavViewController

現状として、MapVCのお気に入りボタンをクリック後、右下のお気に入りタブをタップしてFavVCを開いてもセルに反映されていません。

一度ビルドを停止してまた立ち上げ直すと追加されています。
要するにFavVCのTableViewのリロードがうまくいっていないだけだと思います。

そこで、
MapVCのお気に入りボタンをタップしたら、FavVCのTableViewがリロードされるようにしたいです。

該当のソースコード

MapViewController.swift

IBAction内のみ掲載します。

Swift

1// お気に入りボタンをタップしたとき 2@IBAction func tappedFavButton(_ sender: Any) { 3 4 favPlaces.append(selectedSearchAnnotationTitle ?? "") 5 favUserDefaults.set(favPlaces, forKey: "favPlaces") 6 7 favAddresses.append(placeAddressLabel.text ?? "") 8 favUserDefaults.set(favAddresses, forKey: "favAddresses") 9}
FavViewController.swift

目的はTableViewのリロードなので、viewDidLoad()内にUserDefaultsに関していろいろ書いてありますが、省略させていただきます。

Swift

1import UIKit 2 3var favPlaces = [String]() 4var favAddresses = [String]() 5 6let favUserDefaults = UserDefaults.standard 7 8class FavViewController: UIViewController, UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource { 9 10 @IBOutlet weak var favSearchBar: UISearchBar! 11 @IBOutlet weak var favTableView: UITableView! 12 13 override func viewDidLoad() { 14 super.viewDidLoad() 15 16 // 省略 17 } 18 19 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 20 return favPlaces.count 21 } 22 23 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 24 let cell = tableView.dequeueReusableCell(withIdentifier: "FavCell", for:indexPath) 25 26 if favPlaces.isEmpty == false { 27 cell.textLabel?.text = favPlaces[indexPath.row] 28 cell.detailTextLabel?.text = favAddresses[indexPath.row] 29 30 } else { 31 cell.textLabel?.text = "お気に入りはありません" 32 } 33 34 return cell 35 } 36}

試したこと1

まずはFavViewController.swiftのviewDidLoad()内にreloadData()メソッドを書きましたが、反映されませんでした。
タブビューですとビルド直後に実行されてしまっているのでしょうか……。

FavViewController.swift

Swift

1override func viewDidLoad() { 2 super.viewDidLoad() 3 4 favTableView.reloadData() // お気に入りボタンタップ後、反映されず。 5}

試したこと2

MapViewController.swiftのIBAction内の最後に以下のように書きました。

MapViewController.swift

Swift

1// お気に入りボタンをタップしたとき 2@IBAction func tappedFavButton(_ sender: Any) { 3 4 favPlaces.append(selectedSearchAnnotationTitle ?? "") 5 favUserDefaults.set(favPlaces, forKey: "favPlaces") 6 7 favAddresses.append(placeAddressLabel.text ?? "") 8 favUserDefaults.set(favAddresses, forKey: "favAddresses") 9 10 let favVC = FavViewController() // これを追加 11 favVC.favTableView.reloadData() // これを追加(ここにエラー) 12}

しかし、実行してMapVCのお気に入りボタンをクリックすると、favVC.favTableView.reloadData()の行に以下のエラーが出ます。

Swift

1Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

Segueで繋がっていない場合、別ファイルの変数にどのようにアクセスすればいいのかあまり理解できておりません。
適切な方法がありましたら、ぜひ教えていただきたいです。

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

Xcode 11.6
Swift 5

ここまで読んでくださり、ありがとうございます。
質問に至らぬ点があるかもしれませんが、どうぞよろしくお願いいたします。

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

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

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

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

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

TsukubaDepot

2020/08/31 08:28

ここまで回答を書いて気づいたのですが、このアプリケーションは TabBar を使って2つの ViewController を切り替えているのでしょうか。 もしそうであれば(あるいは、NavigationBar などを使って遷移しているのであれば)、そのことを書いていただいた方が、より適切な回答がつくかと思います(ちなみに、以下の回答はモーダル遷移などを前提に書いていますが、それ以外の遷移方法でも適用できるとは思います)。
unagimochimochi

2020/08/31 08:39

いつもご回答ありがとうございます。 おっしゃる通り、TabBarで切り替えています。普段Segueでつないでいる方法が通用せず困っておりました。 回答者様の助言により、viewDidAppear(animated:) 内に favTableView.reloadData() を記載したところ、MapVCのお気に入りボタンをタップするたびFavVCのセルに場所の名前と住所が追加されるようになりました。 ただ、グローバル変数があまりよろしくないとのことですので、FavVCのプロパティとする方向に変更したいと思います。 TabBarであることがわかりやすいよう、質問を編集させていただきます。ご指摘ありがとうございます。
TsukubaDepot

2020/08/31 08:43

TabBar を使っているのであれば、データ管理は Singleton がいいという話を聞いたことがあります。 TabBar の場合、どの ViewController からどの ViewController を呼び出すのかが一意に決まりませんので、Singleton という形でデータを管理するクラスを作成し、それに各 ViewController からアクセスするのが良いかと思います(present()使った表示であれば、親子関係があるので呼び出した ViewController のインスタンスを取得するのは容易ですが、TabBar の場合はそれができません)。
unagimochimochi

2020/08/31 08:50

有益な情報をありがとうございます。 TableViewのリロード問題は解決しましたので、ベストアンサーにさせていただきました。 Singletonについてはまた別の問題となってきそうですね。挑戦してみてわからないことがあれば改めて質問します。ありがとうございました!
guest

回答1

0

ベストアンサー

現在の流れであれば、favPlaces, favAddresses ともにグローバル変数として定義してあるため、どのクラスからも見える作りとなっています(この方法は決してお勧めできる方法ではありませんが、とりあえず現状のコードを使う方法で説明します)。

なので、「TableView をリロードする」という流れにする必要があるかと思います。

ただし、TableView は FavViewController にあり、MapViewController からは直接見えませんので、何らかの方法で見えるようにする必要があります。

たとえば、質問者さんが

Swift

1 let favVC = FavViewController() // これを追加 2 favVC.favTableView.reloadData() // これを追加(ここにエラー)

という方法で FavViewController を見ようとしていますが、この方法は適切ではありません。

Swift

1 let favVC = FavViewController() // これを追加

は、既に表示されている FavViewController とは全く違う、新しいインスタンスを作成しています。

しかも、新しく作ったインスタンスでは、内部で宣言された

Swift

1@IBOutlet weak var favTableView: UITableView!

などが nil のままとなっていますので、TableViewを表示しようとしたタイミングで実行時エラーが出ていると思われます。

したがって、とりあえず解決させるのであれば、元のビューコントローラ(つまり、FavViewContoller)に戻った段階で TableView をリロードする方法で解決するのではないでしょうか。

このあたりは iOS13 未満と以降とで処理が異なってきますが、両方に使える方法として

  1. 画面遷移を Full Screen にする(iOS13のModal遷移はデフォルトだとDismiss時に遷移元のviewWillAppear等が呼ばれない などを参照)
  2. FavViewControllerviewDidAppear(animated:) で tableView をリロードする。

という流れが考えられると思います。


ちなみに、再起動後なら表示される理由が下記のとおりです。

FavViewController.swift

目的はTableViewのリロードなので、viewDidLoad()内にUserDefaultsに関していろいろ書いてありますが、省略させていただきます。

一番大切な部分が抜けています。

再起動したあとには TableView に表示されるということは、再起動後の初回しか UserDefaults を読み込んでいないということが原因です。

なので、UserDefaults に記録したデータを必要に応じて随時読み込む必要があります。

また、favPlaces, favAddresses の変数はFavViewController のプロパティとし、外部からは見えないようにした方がいいかと思います。

したがって、
0. グローバル変数として定義されている favPlaces, favAddresses を適切な場所に移動させる。

  1. MapViewController でお気に入りを登録する
  2. FavViewController に戻ったら UserDefaults を読み込みなおして配列に反映させる
  3. TableView をリロードする

という流れにする必要があります。

TableView をリロードするタイミングについては、冒頭の回答がヒントになるかと思います。

もちろん、全体の設計を見直してプロトコル指向にするなど他の方法もあるかと思いますので、その辺りは適切に対応していただければと思います。

投稿2020/08/31 07:33

TsukubaDepot

総合スコア5086

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問