NEW: Subscribe to Hacking with Swift+ and accelerate your learning! >>

SOLVED: SceneDelegate.swift for UISplitViewController inside UITabBarController

Forums > iOS

I have a split view controller inside a tab bar controller. When a table row is tapped in the master view controller of split view controller, the delegate doesn't appear to trigger in the detail view controller and the 'selectedWord' value isn't passed.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let selectedWord = wordsDisplayed[indexPath.row]
        print("selectedWord in didSelectRowAt in wordsView is: \(selectedWord.languageWord)")
        delegate?.wordSelected(selectedWord)
        if let detailViewController = delegate as? wordsDetailView,
        let detailNavigationController = detailViewController.navigationController {
            splitViewController?.showDetailViewController(detailNavigationController, sender: nil)
        }
}
extension wordsDetailView: WordSelectionDelegate {
    func wordSelected(_ newWord: Word) {
        word = newWord
        print("word in WordSelectionDelegate in wordsDetailView is: \(word!.languageWord.components(separatedBy: "::")[0])")
        navigationItem.title = word?.languageWord.components(separatedBy: "::")[0]
        getImage()
        save.isEnabled = false
        clear.isEnabled = true
        share.isEnabled = true
    }
}

When a button is tapped in the detail view controller which depends on the selectedWord value, the program crashes at the print statement, as it unwraps an unexpected nil value:

@IBAction func save(_ sender: UIBarButtonItem) {
        // Create path.
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        print("word in save in wordsDetailView is: \(word!)")
        let filePath = "\(paths[0])/\(word!.languageWord.components(separatedBy: "::")[1]).png"
        print("filePath in save in DetailWord is: \(filePath)")
        // Save image.
        do {
        try wordImage?.image?.pngData()?.write(to: URL(fileURLWithPath: filePath))
        } catch {
            print("Error saving image!")
        }
        save.isEnabled = false
    }

The 'word' variable is declared at top of class as:

var word: Word? {
        didSet {
          refreshUI()
        }
 }

The print statement in didSelectRowAt is ok, but the one in the detail view controller's extension isn't (nothing prints).

I've got a simpler example that works without a tab bar controller, so I thought the introduction of the tab bar was the culprit. I've got some code in SceneDelegate.swift, that was written pre tabBarController, which handles setting up different view controllers. The 'word' variable and delegate are mentioned. I'm not sure if this needs changed to reflect the addition of another controller (tab bar), and how to go about it.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard
            let splitViewController = window?.rootViewController as? UISplitViewController,
            let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
            let masterWordsController = leftNavController.viewControllers.first as? wordsView,
            let detailWordController = (splitViewController.viewControllers.last as? UINavigationController)?.topViewController as? wordsDetailView
            else { fatalError() }

        let firstWord = masterWordsController.wordsDisplayed.first
        print("firstWord in sceneWillConnectToOptions in SceneDelegate is: \(firstWord!)")
        detailWordController.word = firstWord
        masterWordsController.delegate = detailWordController
        detailWordController.navigationItem.leftItemsSupplementBackButton = true
        detailWordController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
      }
}

   

I would move to NotificationCenter so your code isnt this coupled and yout dont have to do a ton of typecasting :-)

With NotificationCenter you can define "observer" with observe method and then post notification containing your word.

https://www.hackingwithswift.com/example-code/system/how-to-post-messages-using-notificationcenter

https://dev.to/nemecek_f/ios-how-to-notify-parts-of-app-about-changes-and-send-data-in-loosely-coupled-way-34ch

   

Hacking with Swift is sponsored by NSSpain

SPONSORED Announcing NSSpain 2020: Remote Edition! An online, continuous conference for iOS developers. We’ll start on Thursday and finish on Friday, with talks, activities, and lots of fun for 36 hours, non-stop. Sound good? Join us!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

Not logged in

Log in
 

Link copied to your pasteboard.