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

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

新規登録して質問してみよう
ただいま回答率
85.48%
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

解決済

5回答

8376閲覧

SwiftでViewControllerのインスタンスの取得方法について

pascal1623

総合スコア18

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グッド

3クリップ

投稿2019/07/08 13:32

編集2019/07/09 11:27

ネット上を調べるとSwiftでViewControllerをインスタンス化するためには、以下のコードがよく例としてあげられています。

Swift

1let storyboard = UIStoryboard(name: "Main", bundle: nil) 2let firstViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController

storyboard名:Main
ViewController名:FirstViewController

しかし、これで取得したインスタンスを用いてFirstViewController上の部品にアクセスしようとしてもnilになってしまって、上手くインスタンスが取得できていないようです。
(storyboardに配置しているFirstViewContorllerのインスタンスとは別のインスタンスが作成取得されてしまっているのでしょうか?)

storyboard.instantiateViewControllerというのはどのように使用するもので、どのようにインスタンスを作成すればいいのでしょうか。

ご教示頂けますと幸いです。
よろしくお願いいたします。

↓以下追記

Swift

1//FirstViewController 2@IBOutlet weak var labelA: UILabel! 3. 4. 5. 6func test() { 7 labelA.text = value.stringA 8} 9 10```Swift 11 12```Swift 13//SecondViewController 14let storyboard = UIStoryboard(name: "Main", bundle: nil) 15let firstViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController 16firstViewController.loadViewIfNeeded() //追加しました 17firstViewController.test()

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2019/07/10 11:34

遷移した際にとか、遷移先から戻る際にとかではなく、後ろにある?viewControllerを捕まえて要素にアクセスしたいだけなのではないでしょうか?
pascal1623

2019/07/10 11:37

「後ろにある」というのが、今は表示されていない、さっきまで表示されていたviewContorollerということでしたら、その通りです。 何かいい方法ありますでしょうか??
退会済みユーザー

退会済みユーザー

2019/07/10 12:07 編集

単純に子から親ならparentとかだけど、tabbarつかうとどうなんだろ。どういう遷移構造になってるかでも捕まえ方が違うと思うよ。 単純なのはこれとか見てみて→https://teratail.com/questions/31316 こうやって遷移してきたこのViewControllerから遷移元であるあの ViewControllerの要素にアクセスする方法をとかいう具体的な質問なら具体的な回答がつきやすいんじゃないかな?
pascal1623

2019/07/10 12:18

皆さんの回答をもらいまして、instantiateViewControllerというメソッドを使って、ポンと他のviewControllerのインスタンスを取得して使うというのは、あまり一般的ではないということのように感じました。 (これが一番なんでもありで便利なように思ったのですが) ご指摘のようにプログラムのviewControllerの遷移関係によって考えなくてはいけないということになりますでしょうか。 ご回答ありがとうございました。
guest

回答5

0

ベストアンサー

tabBarで表示を切り替えている?ということなので、こんな感じでどうでしょうか?

構成は単純につくって、SecondVCのボタンを押すと、FirstVCのtestメソッドでFirstVCのcountに1を加えて、
コンソールに文字が表示されます。FirstVCに戻るとcountをプリントしますが、きちんと数を受け継いでいるので、
新たにインスタンスを作成しているのではなく、存在しているVCにアクセスしていることが確認できると思います。

FirstViewController/SecondViewControllerの'ViewDidLoad'は、はじめに遷移した際しか呼ばれず、
再度遷移するごとにAppear系/Disappear系のメソッドが呼ばれるので、
UIObjectなどへの変更はこの中で、MasakiHoriさんの回答のようにするのがいいのかな?

イメージ説明

swift

1 2import UIKit 3 4class FirstViewController: UIViewController { 5 6 var count: Int = 0 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 print("FirstVC/viewDidLoad") 11 } 12 13 override func viewDidAppear(_ animated: Bool) { 14 super.viewWillAppear(animated) 15 print("FirstVC/viewDidAppear") 16 printCount() 17 } 18 19 override func viewDidDisappear(_ animated: Bool) { 20 super.viewDidDisappear(animated) 21 print("FirstVC/viewDidDisappear") 22 } 23 24 func test() { 25 count += 1 26 printCount() 27 } 28 29 func printCount() { 30 print("count:", count) 31 } 32} 33 34class SecondViewController: UIViewController { 35 36 override func viewDidLoad() { 37 super.viewDidLoad() 38 print("SecondVC/viewDidLoad") 39 } 40 41 override func viewDidAppear(_ animated: Bool) { 42 super.viewWillAppear(animated) 43 print("SecondVC/viewDidAppear") 44 } 45 46 override func viewDidDisappear(_ animated: Bool) { 47 super.viewDidDisappear(animated) 48 print("SecondVC/viewDidDisappear") 49 } 50 51 @IBAction func btnDidTap(_ sender: UIButton) { 52 print("SecondVC/btnDidTap") 53 // こんな感じでアクセスできるようですよ。 54 let tab = tabBarController 55 if let firstVC = tab?.viewControllers?[0] as? FirstViewController { 56 firstVC.test() 57 } 58 } 59}

投稿2019/07/10 19:24

編集2019/07/10 19:49
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

pascal1623

2019/07/11 11:10

丁寧なコードや画面まで示していただきまして恐れ入ります。 そのように他のVCにアクセスさせていただきます。 またあまり他からVCをいじるのはよくないというのがよくわかりましたので、示していただいたように最低限にして、viewWillAppearなどを活用していきたいと思います。 ありがとうございました。
guest

0

表示されるライフサイクルでviewDidLoad()が呼ばれるので、インスタンスを生成したたけでは、ロードされないし、アクセスもできないですね。FirstViewControllerを画面に表示するコードはどこにあるのでしょうか?

投稿2019/07/09 16:55

k2moons

総合スコア184

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

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

pascal1623

2019/07/10 11:18

ご回答ありがとうございます。 FirstViewControllerはinitial ViewControllerでして、一旦表示させております。 もちろんlabelA.textにstringAは代入できて、stringAが表示されます。 viewControllerの切り替えはtabBarになっていて、tabでSecondViewControllerに切り替えて、そこからFirstViewControllerのtest()を呼ぶとlabelAがnilであるというエラーが出てしまうということについての相談です。 トンチンカンだったらすみません。
guest

0

UIViewControllerはそれが必要になるまでviewをロードしません。
ですので、常にこの段階でviewはロードされているかということを考えておく必要があります。

あなたのコードのtestメソッドが呼ばれた時にviewが必ずしもロードされているとは限りません。
ですのでこの場合も下に例示したコードのように自身のプロパティを変更するだけにとどめ、viewが表示される前つまりviewWillAppearメソッド内で、その値をUIに反映するようにしてください。
これが回りくどいと思う場合はtestメソッドの中でviewを強制的にロードしてからUIに反映するようにします。

外部にviewの存在を意識させないことを心がけてください。

####これは回答ではありません

他のUIViewControllerのUI要素への直接のアクセスは悪手になりやすいので

swift

1class FirstViewController: UIViewController { 2 3 var title: String = "" 4 @IBOutlet private var titleLabel: UILabel! 5 6 override func viewWillAppear(animated: Bool) { 7 super.viewWillAppear(animated) 8 titleLabel.text = title 9 } 10}

のようにして、通常のプロパティ経由で内容を表示させるほうがいいです。
値をどのように表示させるかの責務はそのUIViewControllerが負うという考え方です。

この方法ですとUIViewControllerのviewがロードされていようがいまいが使う側には無関係になります。

利点として表示の仕方を変えたりUI要素の名前を変えたりしても使う側は何も変更する必要がないという点が挙げられます。

投稿2019/07/09 08:02

編集2019/07/09 13:13
MasakiHori

総合スコア3384

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

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

pascal1623

2019/07/09 11:46

回答ありがとうございます。 要約したコードを記載させていただきました。 SecondViewControllerで変更した状態を、FirstViewControllerに反映したいということなのですが、この方法はよくないのでしょうか。 delegateも考えるのですが、どんな場面で使うかも理解しておらず、どうやればいいか、どうもはっきりしません。
pascal1623

2019/07/10 11:24

一旦表示させたviewControllerのUIへなぜアクセスできない!?という疑問はあるのですが、皆様の回答をいただきまして、そういう必要性はまずなく、そういうプログラムはおかしいということがわかったように思います。 ご指摘のようにviewWillAppearの中にコードを記述しての解決を目指そうと思います。 大変ありがとうございました。
guest

0

instantiateViewControllerはそのViewControllerから派生したクラス(FirstViewController)が生成されるだけで、その時点ではまたviewは作成されていません。
viewプロパティに初めてアクセスするときに生成されます。
loadViewIfNeededを明示的に呼ぶか、適当にviewプロパティにアクセスすれば作成されると思います。

viewが生成されたらFirstViewController.viewLoadedが呼ばれるので、そのタイミングを見てみたらいいと思います。

投稿2019/07/08 14:36

toki_td

総合スコア2850

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

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

pascal1623

2019/07/09 11:41

回答をいただきましてありがとうございます。 指摘のようにコードにloadViewIfNeededを追加したところ、labelAがnilではなくなり表示を変更することができました。 FirstViewControllerを1回表示させているのに、そこのインスタンスにアクセスできないというのは戸惑っています。 FirstViewControllerはずっと一つ生成されていて、そこにアクセスしているつもりで考えていましたが、これば全く謝りということでしょうか。 適当にviewプロパティにアクセスすれば作成されるということでしたが、labelAは作成されずnilでstringAを代入しようとするとエラーが出てします。 viewDidLoadは作成時の初期化などを入れてあるので、それがまた呼ばれると問題になりそうな気もしています。
guest

0

Storyboard の FirstViewController を選択して右側の設定で Storyboard ID の欄に FirstViewController と入力されているか確認してください。withIdentifier はこの Storyboard IDを参照します。なので別のインスタンスではないです。
また今回の関連としてStoryboard で→がついた VIewController を呼び出すには下記コードだけです。
もちろん Storyboard IDを指定しても良い。

swift

1storyboard.instantiateInitialViewController()

投稿2019/07/08 14:31

編集2019/07/08 14:33
TakuyaAso

総合スコア1361

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

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

pascal1623

2019/07/09 11:31

回答をいただきましてありがとうございます。 storyboard IDは入力してありました。 追記のように、最初はloadViewIfNeededというのが入っておりませんでして、 そうすると、labelAというのがnilになってしまってエラーが出る状況でした。 ネットを調べていても、あまりこのことが載っていなくてつまずいておりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問