

Swiftでの別画面からのTableViewの更新

メインとなるListViewのtableview: UITableViewの更新を サブのPostViewから投稿するたびに行いたいのですが

PostViewの

[code]

    @IBAction func cellAdd(_ sender: Any) {
            let storyboard: UIStoryboard = self.storyboard!
    
            let listView = storyboard.instantiateViewController(withIdentifier: "ListView") as! ListView
    
            let postText = textField.text!
            self.data.insert(postText, at: 0)
            userDefaults.register(defaults: ["DataStore": "default"])
    
            userDefaults.set(data, forKey: "DataStore")
    
            listView.tableView?.reloadData()
    
    }
    
[/code]

でも更新されません

[code]

    listView.tableView?.beginUpdates()
    listView.tableView?.insertRows(at: [IndexPath(row: 0, section: 0)],
                                  with: .automatic)
    listView.tableView?.endUpdates()
    
[/code]

でも更新できません

検索しても他画面からの更新はのっていません

どうしたらできるでしょうか？

追記

PostView

@IBAction func cellAdd(_ sender: Any) {  
let storyboard: UIStoryboard = self.storyboard!

[code]

        let listView = storyboard.instantiateViewController(withIdentifier: "ListView") as! ListView
    
        let postText = textField.text!
        listView.data.insert(postText, at: 0)
    
        listView.tableView?.reloadData()
    }
    
[/code]

に ボタンを設置して

押したら ListView

class ListView: UIViewController, UITableViewDataSource, UITableViewDelegate {

[code]

    @IBOutlet weak var tableView: UITableView!
    
    var data: [String] = []
    
    let userDefaults = UserDefaults.standard
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        tableView.dataSource = self
        tableView.delegate = self
    
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let postcell = tableView.dequeueReusableCell(withIdentifier: "postcell")!
        postcell.textLabel?.text = data[indexPath.row]
        return postcell
    }
    
[/code]

に 移動して

という流れですが

Tab ControllerでもどったときにTableViewが更新されていません

ListView が 0 , PostView が 1 です

質問の初期では

[code]

        listView.tableView?.reloadData()
    
[/code]

が

[code]

    listView.tableView?.beginUpdates()
    listView.tableView?.insertRows(at: [IndexPath(row: 0, section: 0)],
                                  with: .automatic)
    listView.tableView?.endUpdates()
    
[/code]

です

追記  
エラーメッセージは以下の通りです

[code]

    2020-04-06 00:28:33.738976+0900 P1-49[83809:6003737] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIView 0x7fe823d076f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key tableView.'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x000000010210472b __exceptionPreprocess + 331
        1   libobjc.A.dylib                     0x00000001016a8ac5 objc_exception_throw + 48
        2   CoreFoundation                      0x0000000102104299 -[NSException raise] + 9
        3   Foundation                          0x000000010111d586 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 289
        4   UIKitCore                           0x0000000105e4f5dc -[UIView(CALayerDelegate) setValue:forKey:] + 171
        5   UIKitCore                           0x000000010560528d -[UIRuntimeOutletConnection connect] + 109
        6   CoreFoundation                      0x00000001020f0d71 -[NSArray makeObjectsPerformSelector:] + 305
        7   UIKitCore                           0x0000000105601fd3 -[UINib instantiateWithOwner:options:] + 1810
        8   UIKitCore                           0x000000010537ef0f -[UIViewController _loadViewFromNibNamed:bundle:] + 382
        9   UIKitCore                           0x000000010537f899 -[UIViewController loadView] + 177
        10  UIKitCore                           0x000000010537fba8 -[UIViewController loadViewIfRequired] + 172
        11  UIKitCore                           0x00000001053803c8 -[UIViewController view] + 27
        12  UIKitCore                           0x00000001052b66a8 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 472
        13  UIKitCore                           0x00000001052b5b31 -[UITabBarController transitionFromViewController:toViewController:] + 59
        14  UIKitCore                           0x00000001052b1e2d -[UITabBarController _setSelectedViewController:] + 410
        15  UIKitCore                           0x00000001052b1c01 -[UITabBarController setSelectedViewController:] + 109
        16  UIKitCore                           0x0000000105e41e01 +[UIView(Animation) performWithoutAnimation:] + 90
        17  UIKitCore                           0x00000001052abe71 -[UITabBarController _selectDefaultViewControllerIfNecessaryWithAppearanceTransitions:] + 506
        18  UIKitCore                           0x00000001052ace1a -[UITabBarController viewWillAppear:] + 213
        19  UIKitCore                           0x0000000105385dd3 -[UIViewController _setViewAppearState:isAnimating:] + 687
        20  UIKitCore                           0x000000010538653e -[UIViewController __viewWillAppear:] + 131
        21  UIKitCore                           0x0000000105387d29 -[UIViewController viewWillMoveToWindow:] + 696
        22  UIKitCore                           0x0000000105e3857d -[UIView(Hierarchy) _willMoveToWindow:withAncestorView:] + 656
        23  UIKitCore                           0x0000000105e49451 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 456
        24  UIKitCore                           0x00000001059b85ec -[UIWindow addRootViewControllerViewIfPossible] + 1027
        25  UIKitCore                           0x00000001059b8957 -[UIWindow _setHidden:forced:] + 289
        26  UIKitCore                           0x00000001059cb5b6 -[UIWindow makeKeyAndVisible] + 42
        27  UIKitCore                           0x000000010597b578 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4555
        28  UIKitCore                           0x00000001059806f6 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1617
        29  UIKitCore                           0x00000001051c6222 __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 904
        30  UIKitCore                           0x00000001051ceb1a +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
        31  UIKitCore                           0x00000001051c5e38 -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 236
        32  UIKitCore                           0x00000001051c6794 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1091
        33  UIKitCore                           0x00000001051c4b06 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 782
        34  UIKitCore                           0x00000001051c47bd -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 433
        35  UIKitCore                           0x00000001051c9502 __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 576
        36  UIKitCore                           0x00000001051ca15c _performActionsWithDelayForTransitionContext + 100
        37  UIKitCore                           0x00000001051c9269 -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 223
        38  UIKitCore                           0x00000001051ce21c -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
        39  UIKitCore                           0x000000010597efd8 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 514
        40  UIKitCore                           0x000000010553678a -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
        41  FrontBoardServices                  0x000000010e240175 -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
        42  FrontBoardServices                  0x000000010e249f26 __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 283
        43  FrontBoardServices                  0x000000010e249750 __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
        44  libdispatch.dylib                   0x0000000104476db5 _dispatch_client_callout + 8
        45  libdispatch.dylib                   0x000000010447a2ba _dispatch_block_invoke_direct + 300
        46  FrontBoardServices                  0x000000010e27b196 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
        47  FrontBoardServices                  0x000000010e27ae4e -[FBSSerialQueue _performNext] + 451
        48  FrontBoardServices                  0x000000010e27b3e3 -[FBSSerialQueue _performNextFromRunLoopSource] + 42
        49  CoreFoundation                      0x000000010206bc11 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
        50  CoreFoundation                      0x000000010206b493 __CFRunLoopDoSources0 + 243
        51  CoreFoundation                      0x0000000102065b4f __CFRunLoopRun + 1231
        52  CoreFoundation                      0x0000000102065332 CFRunLoopRunSpecific + 626
        53  GraphicsServices                    0x000000010b1952fe GSEventRunModal + 65
        54  UIKitCore                           0x00000001059821d2 UIApplicationMain + 140
        55  P1-49                               0x0000000100dc421b main + 75
        56  libdyld.dylib                       0x00000001044eb861 start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    (lldb)
    
[/code]


CC BY-SA 4.0
2020-04-03T08:34:31.703
65328
2020-04-05T16:37:05.473
2020-04-05T16:35:39.053
3060
39481
question
swift
Swift 別画面からのTableViewの更新


コメントにも書きましたが、あなたのコードの中で本質的に問題があるのは、ここの部分です。

[code]

        let listView = storyboard.instantiateViewController(withIdentifier: "ListView") as! ListView
    
[/code]

これでは、storyboardに定義された`ListView`のインスタンスを新たに作成してしまいます。そのインスタンスは、`UITabBarController`の0番として表示されている`ListView`のインスタンスとは別のインスタンスだと言うことになります。

そのメソッドを例えば次のようにして見てください。

[code]

        @IBAction func cellAdd(_ sender: Any) {
            guard let listVC = tabBarController?.viewControllers?[0] as? ListViewController else {
                print("Cannot get listVC from tab bar controller")
                return
            }
    
            let postText = textField.text ?? ""
            listVC.data.insert(postText, at: 0)
    
            //listVC.tableView?.reloadData()
            //または
            listVC.tableView?.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
        }
    
[/code]

  * view controllerに`ListView`なんてクラス名がついているのはあまりにも気持ちが悪いので、`ListViewController`にしてあります。あなたのプロジェクトでクラス名を変えられないなら読み替えてください。同じく`listView`を`listVC`にしてありますが、もちろんコードの動作には関係ありません。

**注** storyboardを使用しているアプリでは、ソースファイル(.swift)上でview
controllerのクラス名を変更した場合には、storyboardでも対応するCustom
Classの設定を更新してやる必要があります。ご質問の「追記」に記載されたエラーはこれが正しくできていない場合に起こるものなので、storyboardの設定を見直してください。

  * 肝心なのは`tabBarController?.viewControllers?[0]`と言う書き方で、自画面を表示している`UITabBarController`の0番に割り当てられているview controllerを取り出すことができる、と言う点です。

* * *

これは直接は関係ないのですが、`ListView`(`ListViewController`)の中の以下のコードは書き換えた方が良いでしょう。

[code]

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let postcell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath)
            postcell.textLabel?.text = data[indexPath.row]
            return postcell
        }
    
[/code]

`dequeueReusableCell(withIdentifier:)`と言う`for:`なしのメソッドは、Optional型を返します。それは`nil`になる可能性がある、と言うことです。iOSのメソッドの中には、「型はOptionalだけで、実は決して`nil`にはならない」なんて場合もありますが、このメソッドの場合には、実際に`nil`が返ってくる可能性があるので、`!`で強制アンラップなんかしてはいけません。

(実際iOSのバージョンによっては即座にアプリがクラッシュします。)

`dequeueReusableCell(withIdentifier:for:)`と言う`for:`付きのメソッドを使えば、非Optionalのセルが返ってくるので、強制アンラップなんて危険なことはする必要がなくなります。

* * *

なお、今回のように「特定のview controllerにデータが置かれていて、それをそのview
controllerのプロパティやメソッドを通じて操作する」なんてことをやっていると、画面数が増えてきたときにどうしようもなくなってくることが多いです。

(`UITabBarController`や`UINavigationController`が複雑に絡まって、どうやれば目的のview
controllerにたどり着けば良いのかがとんでもなく難しくなってくるし、ちょっと画面構成を変えるだけで、あちこち書き換えないといけなくなってくる…などなど。)

特定のview controllerとは独立したデータモデルを作成して、各view
controllerでは、そのデータモデルから、変更があれば通知を受け取る、なんてつくりにすると、アプリが大規模化してきた場合にも対応がしやすくなります。書き換える対象が増えますし、本来はご質問の趣旨ともだいぶ外れてしまうので、ここでは詳細には述べませんが、将来の課題とされた方が良いでしょう。


CC BY-SA 4.0
2020-04-05T14:40:24.150
65373
2020-04-05T16:37:05.473
2020-04-05T16:37:05.473
13972
13972
65328
answer