回答編集履歴

2

そのまま適用するとスコープの問題でエラーが出る可能性があるので変更した。

2021/02/19 05:11

投稿

TsukubaDepot
TsukubaDepot

スコア5086

test CHANGED
@@ -138,7 +138,15 @@
138
138
 
139
139
  // viewDidLoad() 内部などで
140
140
 
141
+ if let index = self.children.firstIndex(where: { vc -> Bool in
142
+
143
+ return vc is CabinViewController
144
+
145
+ }) {
146
+
141
-   cabinVC = self.chidren[index] as! CabinViewController
147
+    cabinVC = self.chidren[index] as! CabinViewController
148
+
149
+ }
142
150
 
143
151
  ```
144
152
 

1

回答の変更

2021/02/19 05:11

投稿

TsukubaDepot
TsukubaDepot

スコア5086

test CHANGED
@@ -1,16 +1,32 @@
1
+ コメントを受けて修正します。
2
+
3
+
4
+
1
- とりあえず、ご質問の内容から確実に言えることだけご指摘します。
5
+ ~~とりあえず、ご質問の内容から確実に言えることだけご指摘します。
6
+
2
-
7
+ ~~
8
+
3
-
9
+ 結論としては、はやりインスタンスの関係を正しく把握しない状態でコーディングされていることが原因です。
4
-
10
+
11
+
12
+
5
- ```Swift
13
+ ```Swift
6
-
14
+
7
- let viewControllerB = ViewControllerB()
15
+ let let cabinVC = CabinViewController()
8
-
16
+
9
- ```
17
+ ```
18
+
19
+
20
+
10
-
21
+ という行があり、たしかに `CabinViewController` はインスタンス化されます。
22
+
23
+
24
+
11
-
25
+ しかし、StoryBoard 状に配置した Container View には`CabinViewController` が紐づけられていいるはずで(`embeded segue`として関連づけられているはず)で、ここで改めてインスタンス化した `CabinViewController` とは全く無関係になっています。
12
-
26
+
27
+
28
+
13
- という行があり、しかに `ViewControllerB` (実際は`CabinViewController`はインスタンス化されます、インスタンス化されるだけであり、`viewDidLoad()`などのライフサイクルに関するメソッドや、
29
+ コード内でインスタンス化された `CabinViewController` 単にインスタンスが出来だけであり、`viewDidLoad()`などのライフサイクルに関するメソッドや、
14
30
 
15
31
 
16
32
 
@@ -48,8 +64,164 @@
48
64
 
49
65
 
50
66
 
51
- この行にある`myTableView.reloadData()`のメソッドチェインに失敗し、ここで実行時エラーとなるのが今回のエラーの原因となります。
52
-
53
-
54
-
55
- UI部品のインスタンス化やイフサイクルに関する処理を行わせるためには、`present` やそれに類似するメソッドを使う必要がありますので、ご確認いただけまでしょうか
67
+ この行にある`myTableView.reloadData()`のメソッドチェインに失敗し、実行時エラーとなっています。
68
+
69
+
70
+
71
+ 以上が今回原因です。
72
+
73
+
74
+
75
+ ###対策
76
+
77
+
78
+
79
+ さて、追記していただいたコードや StoryBoard 上の階層から想像すると、ContainverView を使い、そこで TableView を表示を(つまり、`CabinViewController` の表示を)されています。
80
+
81
+
82
+
83
+ そうすると、必要な作業は、Container View に入れられた `CabinViewController` のインスタンス(より具体的に言うと、メモリ上に展開されたアドレス)を調べ、そこから直接 `CabinViewController` のメソッドを操作することになると思われます。
84
+
85
+
86
+
87
+ Container View に追加された (一般的に言うところの)View Controllerのインスタンスは、`children` という `[UIViewController]`の配列に入ますので、そこから `CabinViewController` のインスタンスを探し出す必要があります。
88
+
89
+
90
+
91
+ 全てコードベースで Container View に追加するのであれば、それは自明なのですが、StoryBoard で追加したのであれば、自分で探す必要があります(ちなみに、Container View というのは、実際には UIView に過ぎず、StoryBoard で紐づければ一連の厄介な手続きが自動化されるだけの話です。逆にいうと、自動化されるために手間がかかる作業も増えるということです)。
92
+
93
+
94
+
95
+ Container View が一つだけであれば、配列のインデックスを決め打ちで調べることも可能ですが、安全性や、あるいは今回みたいに複数の Container View を使うのであれば、なんらかの方法で調べる必要があります。
96
+
97
+
98
+
99
+ たとえば、`viewDidLoad()`で
100
+
101
+
102
+
103
+ ```Swift
104
+
105
+ if let index = self.children.firstIndex(where: { vc -> Bool in
106
+
107
+ return vc is CabinViewController
108
+
109
+ }) {
110
+
111
+ print("Cabin:", index)
112
+
113
+ }
114
+
115
+ ```
116
+
117
+
118
+
119
+ みたいな方法を使い、`children` に入っているインスタンスとのパターンマッチを行うことでインデックスを調べる必要があります。
120
+
121
+
122
+
123
+ 正確に言うと、`is` 演算子は `CabinViewController` クラスを元にして作られたインスタンスとのマッチングであり、仮に `children` の内部に複数の`CabinViewController`から作られたインスタンスが存在するのであれば、それはこの方法で調べることはできませんし、全体構成を根本的に見直す必要があると思います
124
+
125
+
126
+
127
+ それはさておき、上記の方法で `index` がわかれば、
128
+
129
+
130
+
131
+ ```Swift
132
+
133
+ // クラスのプロパティとして宣言
134
+
135
+ var cabinVC: CabinViewController?
136
+
137
+
138
+
139
+ // viewDidLoad() 内部などで
140
+
141
+   cabinVC = self.chidren[index] as! CabinViewController
142
+
143
+ ```
144
+
145
+
146
+
147
+ のような方法で、`vc` に `CabinViewController` のインスタンス(具体的なメモリ上のアドレス)を得ることができますので、あとは
148
+
149
+
150
+
151
+ ```Swift
152
+
153
+ cabinVC?.reloadTabeleDate()
154
+
155
+ ```
156
+
157
+
158
+
159
+ のような感じで、直接 `CabinViewController` のメソッドを操作することになります。
160
+
161
+
162
+
163
+ ### delegate の適用
164
+
165
+
166
+
167
+ 今回のようなパターンであれば、無理に delegate パターンに持ち込む必要はないと思いますし、上記のようになんらかの方法で対象となるインスタンスを探すのであれば、delegate としてインスタンスを保持する理由もあまりないとおもます(結果として、行っていることは同じなので)。
168
+
169
+
170
+
171
+ もちろん、`CabinViewController` を汎用的なクラスとして使いたいということであれば、delegate パターンを適用することになりますが、その場合には `CabinViewController` のインスタンス化の流れから根本的に見直す必要があると思います。
172
+
173
+
174
+
175
+ たとえば、StoryBoard で Container View を使うのではなく、UIView を配置し、`instantinateViewController` で従属させたいView Controllerを正しく初期化させ、`addChild` で child として追加し、その view を UIView のサブビューとして登録し、必要に応じて画面全面に持ってくるという流れを全て手動で行えば、また話は違ってくると思います(それでも、delegate パターンを使う必然性はあまりないと思います)。
176
+
177
+
178
+
179
+ ### 全体の構成
180
+
181
+
182
+
183
+ もう一つ考えていただきたいのは、全体の構成です。
184
+
185
+
186
+
187
+ ViewController 内部に多くの Container View を取り込み、複数の View Controller を扱っている時点で、もはや質問者さんご自身が管理不能な状態に陥っているように思えます。
188
+
189
+
190
+
191
+ 全体像が見えないのでなんとも言えないのですが、一つの画面に対してこれほどたくさんの View Controller を適用する必要があるのか、もう一度設計をよく見直された方がいいかもしれません。
192
+
193
+
194
+
195
+ ざっとみた感じであれば、一つの View Controller 内部に Table View を配置し、適切に制約(constraint)などを設定すれば、それで住むだけの話のようにも思えます。
196
+
197
+
198
+
199
+ ただ、これは期待される構成としてどのような構成を考えていらっしゃるのかよく聞かない限り判断できませんが、ただこの内容のご質問だと、聞いている方も把握するのは難しいのではないかと感じています。
200
+
201
+
202
+
203
+ ### 今後の方針として
204
+
205
+
206
+
207
+ それでもやはり Container View を使って作りたい、ということであれば、
208
+
209
+
210
+
211
+ **ひとつの View Controller に一つの Container View だけを持つサンプルを作り、そこから Container View 内部に配置した View Controller のインスタンスを特定し、操作する**
212
+
213
+
214
+
215
+ という、ごく単純で明快なサンプルを作り、そこで納得のゆく結果を得てから拡張されるのが良いかと思います。
216
+
217
+
218
+
219
+ 別件のご質問も拝見しましたが、そこで指摘されているように View と View Controller の違い、特に役割の違いについて誤解を受けているように私も感じました。
220
+
221
+
222
+
223
+ もしかしたら、なんらかのサンプルを元にオリジナルのアプリを作ろうとされているのかもしれません。
224
+
225
+
226
+
227
+ でも、結局はごく最小限の構成を理解しないことにはそれより大きい構成を作ることは難しい話なので、まずはごく簡単なサンプル作りから始め、着実に積み重ねられた方が良いのではないでしょうか。