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

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

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

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

Q&A

解決済

2回答

2706閲覧

Swift デリゲートを使って値を渡して遷移元を再描画させる方法

torkia

総合スコア24

Swift

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

0グッド

0クリップ

投稿2018/08/27 06:31

編集2018/08/27 15:30

遷移元の画面に値を渡してその値によって遷移元を再描画させたいのですが、セグエで遷移して戻ると(dismissやunwindなどで)遷移元の画面は遷移前の状態のままで変化がありません。
そこで、デリゲートを使ってみたのですが、それでも遷移元には反映されていません。
コード記述のどこかが間違っているのか、やり方が間違っているのか・・・
解る方がいらっしゃいましたら教えて頂けないでしょうか。
宜しくお願い致します。

詳細説明

ナビゲーションコントローラーを1枚目のテーブルビューに埋め込んで、1枚目のテーブルビューから2枚目のテーブルビューに遷移して→PageViewControllerに遷移したら、コンテンツVCの各ページはスワイプで移動できるようになっています。

画面遷移はセグエを使用しています。

画像の左から4つ目のPageViewControllerのナビゲーションバー上にある「設定」ボタンから、画像下段のSettingViewControllerへ遷移します。

SettingViewControllerにて遷移元に反映させたい設定などをします。

実際に戻る画面は(戻った時に表示される画面)PageViewControllerの管理するコンテンツVCとなるPageContentViewControllerの遷移した時に表示されていたページが表示されます。

サンプルコードではviewの背景色を変えるメソッドにしておりますが、実際は設定項目が複数あるので、ひとつひとつデリゲートメソッドに抜き出して呼び出すよりは、再読込(リロードのような)させられるのならばその方法も知りたいです。

できれば、presentで遷移したような状態になりたいのですが・・・
(presentで遷移すれば再描画されるのですが、テーブルビューに戻るボタンが消えるなどのエラーがでてテーブルビューに戻れなくなってしまって詰まりました)

イメージ説明

サンプルコードで試したこと

SettingViewController内の「OFF/ON]ボタンを選択して戻るボタンを押下すると、デリゲートメソッドのtest1(),test2()の中に記述したprint文はデバッグエリアに出力されるのですが、背景色を変更するようなことにはなりません。

<例> 
設定を「ON」にして「戻る」押下
(ONにするとsoundSettingが1になります)

<print出力>
test1メソッドに入ったsoundSetting: 1
test2メソッドに入ったsoundSetting: 1

<遷移元画面>
変化なし

サンプルコード version Swift3

import Foundation protocol testDelegate: class { var soundSetting:Int { get set } func test1() func test2(soundSetting: Int) }
import UIKit class SettingViewController: UIViewController { weak var testdelegate: testDelegate? var soundSetting:Int = 0 var pageIndex:Int = 0 var selectedVC:Int = 0 var arrayLength:Int = 0 override func viewDidLoad() { super.viewDidLoad() // Viewを閉じる(VCへ戻る)dismisボタン作成 let backDMButton = UIButton() backDMButton.frame = CGRect(x: 0, y: 0, width: 120, height: 30) backDMButton.center = CGPoint(x: self.view.frame.midX, y: 35) backDMButton.setTitle("dismiss戻り", for: .normal) backDMButton.setTitleColor(UIColor.magenta, for: .normal) backDMButton.addTarget(self, action: #selector(backDMVC(sender:)), for: .touchUpInside) self.view.addSubview(backDMButton) // セグメントボタンを作成 let array : NSArray = ["OFF","ON"] let uiSegmentedControl: UISegmentedControl = UISegmentedControl(items: array as [AnyObject]) uiSegmentedControl.frame = CGRect(x: 0, y: 0, width: 200, height: 30) uiSegmentedControl.center = CGPoint(x: self.view.frame.width/2, y: 100) uiSegmentedControl.selectedSegmentIndex = soundSetting uiSegmentedControl.backgroundColor = UIColor.white uiSegmentedControl.tintColor = UIColor.darkGray uiSegmentedControl.addTarget(self, action: #selector(self.segmentChanged(segcon:)), for: UIControlEvents.valueChanged) self.view.addSubview(uiSegmentedControl) } // viewDidLoadを閉じる // セグメントボタン押下時に実行するメソッド func segmentChanged(segcon: UISegmentedControl){ switch segcon.selectedSegmentIndex { case 0: soundSetting = 0 case 1: soundSetting = 1 default: print("Error") } } // セグエで遷移した戻り func backDMVC(sender: AnyObject) { let nav = self.presentingViewController as! UINavigationController let pageViewController = nav.topViewController as! PageViewController pageViewController.soundSetting = soundSetting self.dismiss(animated: true, completion: nil) let delegate = PageContentViewController() self.testdelegate = delegate self.testdelegate?.soundSetting = soundSetting self.testdelegate?.test1() self.testdelegate?.test2(soundSetting: soundSetting) } }
import UIKit class PageContentViewController: UIViewController, testDelegate { //シーン移動の際に設定されるデータ var pageIndex:Int = 0 var selectedVC:Int = 0 var selectedSVC:Int = 0 var soundSetting:Int = 0 override func viewDidLoad() { super.viewDidLoad() (略) } func test1() { self.view.backgroundColor = UIColor.yellow print("test1メソッドに入った: (soundSetting)") } func test2(soundSetting: Int) { if soundSetting == 0 { self.view.backgroundColor = UIColor.red print("test2メソッドに入ったsoundSetting: (soundSetting)") } if soundSetting == 1 { self.view.backgroundColor = UIColor.brown print("test2メソッドに入ったsoundSetting: (soundSetting)") } } }
import UIKit class PageViewController: UIPageViewController, UIPageViewControllerDataSource { // シーン移動の際に渡される値 var selectedVC:Int = 0 // viewControllerで押されたセルのindex var selectedSVC: Int = 0 // SecondViewControllerで押されたセルのindex var arrayLength: Int = 0 var soundSetting: Int = 0 var pageIndex: Int = 0 // ページングするviewControllerを格納する配列のプロパティ宣言 var contentVCs = [UIViewController]() override func viewDidLoad() { super.viewDidLoad() dataSource = self for index in 0..<arrayLength { let contentVC = storyboard?.instantiateViewController(withIdentifier: "PageContentViewController") as! PageContentViewController contentVC.pageIndex = index contentVC.selectedSVC = selectedSVC contentVC.selectedVC = selectedVC contentVCs.append(contentVC) } self.setViewControllers([contentVCs[selectedSVC]], direction: .forward, animated: true, completion: nil) } // viewDidLoad()を閉じる // 設定ボタンからセグエで遷移 @IBAction func goSecondSettingBySegue(_ sender: Any) { performSegue(withIdentifier: "toSecondSetting", sender: nil) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let settingVC = segue.destination as? SettingViewController { settingVC.pageIndex = pageIndex settingVC.selectedVC = selectedVC settingVC.arrayLength = arrayLength settingVC.soundSetting = soundSetting } } // MARK: - UIPageViewControllerDataSource func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let index = contentVCs.index(of: viewController as! PageContentViewController), index > 0 else { return nil } let previousVC = contentVCs[index - 1] return previousVC } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { guard let index = contentVCs.index(of: viewController as! PageContentViewController), index < contentVCs.count - 1 else { return nil } let nextVC = contentVCs[index + 1] return nextVC } }

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

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

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

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

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

guest

回答2

0

ベストアンサー

delegateの設定の仕方が誤っています。

SettingViewController

1let delegate = PageContentViewController() 2self.testdelegate = delegate

のようにしてしまっているので、SettingViewControllerで新たに生成したPageContentViewControllerで書き換えて行ってしまっています。
PageViewControllerで生成した、今表示されているPageContentViewControllerをdelegateとして設定してやる必要があります。

PageViewController

1override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 2 if let settingVC = segue.destination as? SettingViewController { 3 settingVC.pageIndex = pageIndex 4 settingVC.selectedVC = selectedVC 5 settingVC.arrayLength = arrayLength 6 settingVC.soundSetting = soundSetting 7 settingVC.testdelegate = currentVC as? testDelegate // ここに現在表示されているPageContentViewControllerを渡してやる 8 } 9}

currentVCは私が勝手に作った値です。PageViewControllerで今表示しているものを保持しているのであればそれを入れてあげてください。わからなければコメントください。

投稿2018/08/28 03:44

razuma

総合スコア1313

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

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

torkia

2018/08/28 04:58

ご回答ありがとうございます。 教えて頂いたコード記述を試してみたのですが、変化がありませんでした。 let delegate = PageContentViewController() self.testdelegate = delegate の2行を消して let currentVC = contentVCs[pageIndex] settingVC.testdelegate = currentVC as? testDelegate の2行をprepareに追加してみました。 間違っているところをご指摘頂けますでしょうか。
razuma

2018/08/28 05:28

contentVCsからきちんと変更したいViewControllerが受け取れて設定できていれば動くはずです。 サンプルコードを元にして作成し、動いたコードをgithubにあげさせていただきますので相違点などをご確認ください。(もしくはプロジェクトごとどこかにあげていただければそちらをデバッグさせていただきます) https://github.com/RAzuma/DelegateSample
torkia

2018/08/29 06:26

ご回答ありがとうございます。 githubありがとうございました。とても参考になりました。 こちらもgithub公開を試みたのですが、導入と扱いが難しくて断念しました。 >> contentVCsからきちんと変更したいViewControllerが受け取れて設定できて〜 ができていなかったようなので、 UIPageViewControllerDelegateを使って、currentIndexを取得するようにして現在ページを設定するようにしたら遷移元に反映されるようになりました。 let currentVC = contentVCs[pageIndex] を削除して let currentVC = contentVCs[currentIndex]に変更 ですが、遷移元からページ移動するとその設定が他のページに反映されないので困っております。 設定画面で設定したsoundSettingの値をページめくりしても反映させたいのですが、まだ解決方法にたどり着けません。解決できなければ、後々、別項目で質問させて頂こうかと思っているのですが・・・ お時間ありましたら、回答頂けると嬉しいです。
razuma

2018/08/29 07:00

今の状態だとsoundSettingはPageContentViewControllerごとに持っているので self.testdelegate?.soundSetting = soundSettingとしても各ViewControllerごとのsoundSettingが変わるだけになります。 全体として設定したい値であれば、どこか共通で参照できるものを作ったり、今の作り方のままであれば設定した際に全てのViewControllerのsoundSetting値が書き換わるようにするなどもあり、またUserDefaultなどに値を持ってそこを参照するようにする、などなどが考えられるかと思います。 どの方法を選択するかはアプリの設計指針や好みなどにもよるかなと思います。 具体的にコードに起こせそうにないなど、わからない部分があればコメントなどください。
torkia

2018/09/05 03:43

あれから試行錯誤の末、コンテンツVCでの値渡しができるようになったのですが、テーブルビューへ戻った際に設定した値がリセットされるところで詰まりました。 >> 設定した際に全てのViewControllerのsoundSetting値が書き換わる・・・ おっしゃる通り、そうしたいのですが、delegate以外の方法のことでしょうか? >> 具体的にコードに起こせそうにないなど、わからない部分があれば・・・ お言葉に甘えまして、お時間有りましたら教えて頂けると助かります。
razuma

2018/09/14 06:27

すみません。ちょっと忙しくてコメントできてませんでした。 別に質問をあげているようで >どこか共通で参照できるものを作ったり→シングルトン、AppDelegateでの共有 >UserDefaultなどに値を持ってそこを参照するようにする はできているとのことなのでdelegateを使って全てのPageContentViewControllerの背景を 変えるようなものをサンプルコードとしてアップデートしてみました。 https://github.com/RAzuma/DelegateSample 変更点としてはPageContentViewControllerでdelegateの処理をさせていたものを、PageViewControllerにさせるようにしてPageContentViewControllerには色を変えるだけのメソッドを用意させるようにしました。 delegateとはあるクラスで別クラスの処理をさせたいときに使うものになります。 例えば、今回の例で言うとSettingViewControllerで値を設定するが、それを元に他のクラス(PageContentViewController)で処理をしたいと言うような内容になります。 アップデートする前で言うとPageContentViewControllerをdelegateとして設定していましたが PageContentViewControllerは複数あり(contentVCsに入っている)今表示されているもの(pageIndexで指定)だけで処理されてしまうのでひとつのページだけが書き換わってしまっていました。 これを解消して全部を書き換えるためにdelegateはPageViewControllerに持たせておいてPageViewControllerではcontentVCsを持っているので自分の持っているPageContentViewControllerに対して特定の処理を行うような作りにしました。 ちなみに新しい質問の方で「インスタンスを新たに生成している」と言う部分に関してですが let svc = SecondViewController() 上記のコードは「新しいSecoundViewController」を作ると言うコードになります。 おそらく、やりたいことは元々どこかにある「SecondViewController」に対して何かをしたい と言うことになると思いますので、その場合にはその「SecondViewController」をどうにかして参照できるようにする、もしくはdelegateを使って処理したい「SecondViewController」がわかる場所で処理するなどなどのような考え方になります。 オブジェクト指向の考え方がわかってくると上記のようなことが理解できてdelegateも理解できてくるかなと思います。
torkia

2018/09/21 16:26 編集

大変な時期に申し訳ないです。度々のご回答ありがとうございます。 GitHubのコードを参考にして試行錯誤しておりますが、エラーがでてしまいます。 気が向いたときで結構ですので、奮闘中のコードを覗いて頂けたら嬉しいです。
razuma

2018/09/18 08:58

ちょっと遅くなってしまいましたがgithubの方にpullrequestを送らせていただきました。 一応、想定している動きにはなるのではないか?と思います。 わからない部分あればコメントください。
torkia

2018/09/21 06:39

プルリクエストありがとうございます。 想定している動きになりました。 githubの扱いが不慣れでプッシュぐらいしかできなかったものですから、github関連の作業に時間がかかっしまいました。razumaさんのコメント読むだけで自分のミスしている部分が分かっていたのですが、なんとかマージやら修正などを加えてみたかったので返事が遅くなってしまいました。すみません。 razumaさんのサンプルコードを見ながら修正やコピペをしているうちに、プロトコルのプロパティの{get set}部分を削除してしまっていて、他のところでもプロパティの変更処理のコードを忘れていたのが大きな原因でした。 最初のコンテンツVCにプロトコルを継承させていたときよりも、今回教えて頂いたページ管理するVCにプロトコルを継承することで、すっきりしたコードが書けました。とても勉強になりました。 >> 「SecondViewController」をどうにかして参照できるようにする の、他の質問にもヒントを頂き、ありがとうございました。 ですが、PageViewControllerから SecondViewController → ViewControllerの遷移で、既存のインスタンスを呼出す方法が分からず、結局、BarButtonItemを自作して[>back]ボタンとし、そのボタンイベント内で呼び出して値を渡すことぐらいしか思いつきませんでした。もうちょっと考察してみます・・・。 長々とお付き合いありがとうございました。 github上での失礼がありましたら、ご容赦下さいませ。(まだ全然使い方が分かってないです。)
razuma

2018/09/21 09:33

私もあまりgithubを使ったことがなかったので、今回初プルリクエストを出してみました。(してみたかっただけ) 実際に色々とやってみないとなかなか使い方もわからないので何でも試してみることは良いことだと思います。 delegateについても、全くわからない→もやもや→なんとなくわかったかも ぐらいまでには理解できたのかなと思っています。 今後も勉強を進めていきプログラムについての理解が深まってくるとスッキリ!な状態になると思います。(私も初めの頃はdelegateってなんとなくこうやっておけば動くんでしょ?くらいな感じでした。) お疲れ様でした。今後もがんばってください。
guest

0

今回の質問で最初にアップした「該当のサンプルコード」に合わせて、解決した方法を記述しました。

今回のように、全体的に値を共有させたいのであれば、渡すのではなく、UserDefalts, AppDelegate, シングルトンなどの方法が適しているとアドバイスを頂いたので、実際はそうしょうと思っていますが、デリゲートも勉強したかったので、プロトコルを使ったdelegateで、設定画面VC、ページ管理VC、コンテンツVCの3カ所でデリゲートを使った値渡しをしてみました。

razumaさん 
分かりやすい説明のおかげで解決できました。ありがとうございました。

■ プロトコル import UIKit protocol testDelegate: class { var soundSetting:Int {get set} func test(soundSetting: Int) } ■ 設定画面 import UIKit class SecondSettingViewController: UIViewController { // デリゲート処理させるところ weak var testdelegate: testDelegate? (略) // セグエで遷移した戻りのdismiss func backDMVC(sender: AnyObject) { self.testdelegate?.soundSetting = soundSetting // プロパティの変更値をセット self.testdelegate?.test(soundSetting: soundSetting) // PVCのtest()メソッドを処理 self.dismiss(animated: true, completion: nil) } (略) } ■ ページを管理するViewController import UIKit class PageViewController: UIPageViewController, UIPageViewControllerDataSource,UIPageViewControllerDelegate, testDelegate { // 継承 (略) override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let secondSettingVC = segue.destination as? SecondSettingViewController { secondSettingVC.soundSetting = soundSetting secondSettingVC.testdelegate = self // 設定画面のtestdelegateに自身をセット } } // testDelegate func test(soundSetting: Int) { for content in contentVCs { let contents = content as? PageContentViewController contents?.soundSetting = soundSetting // プロパティの変更値をセット contents?.test1() // PCVCのメソッドを処理 contents?.test2(soundSetting: soundSetting) // PCVCのメソッドを処理 } (略) } ■ ページングされるコンテツのViewController import UIKit import AVFoundation class PageContentViewController: UIViewController, AVAudioPlayerDelegate { override func viewDidLoad() { super.viewDidLoad() (略) // アプリ起動の際も背景色をセットするのに使用 test1() test2(soundSetting: soundSetting) } // デリゲートしてもらう処理(設定画面で変更された値で遷移元を再描画させる) func test1() { self.view.backgroundColor = UIColor.yellow } func test2(soundSetting: Int) { if soundSetting == 0 { self.view.backgroundColor = UIColor.red } if soundSetting == 1 { self.view.backgroundColor = UIColor.brown } } (略) }

投稿2018/09/21 07:38

編集2018/10/22 16:31
torkia

総合スコア24

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問