UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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
      }
}

3      

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

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.