Как передать значение из файла SceneDelegate в ViewController (Swift 5)

В одном из методов SceneDelegate я хочу присвоить значение переменной, которая находится в другом ViewController. Как я могу это сделать? Всегда получаю ноль. Я пробовал разные методы, но по какой-то причине они не работают, я хотел использовать обработчик завершения, но, похоже, я не могу этого сделать в методах SceneDelegate

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
        
var viewController: ViewController?
   ...
   //This method works when I click on a cell
   func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
   if let url = URLContexts.first?.url {

      let oauthCompletion: DropboxOAuthCompletion = {
      if let authResult = $0 {
      switch authResult {
      case .success:
         self.dropboxManager.fetchFiles()
         UserDefaults.standard.set(true, forKey:"userAuthorizedInDropbox")
    
         //I want to assign a value here
         self.viewController?.someString = "Some Text"
    
         print("Success! User is logged into Dropbox.")
      case .cancel:
          print("Authorization flow was manually canceled by user!")
      case .error(_, let description):
          print("Error: \(String(describing: description))")
          }
      }
   }
   DropboxClientsManager.handleRedirectURL(url, completion: oauthCompletion)
  }
} 

...
class ViewController: UIViewController {
   ...
   //But it's still nil
   var someString: String?
   ...
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
   dropboxManager.openDropboxAutorization(controller: self)
   }
}

.....
class MainTabBarController: UITabBarController {
let viewController: ViewController = ViewController.loadFromStoryboard()
   override func viewDidLoad() {
        super.viewDidLoad()
    viewControllers = [
            generateVC(rootViewController: viewController, image:           nil, title: "Import")
            ...
        ]

private func generateVC(rootViewController: UIViewController, image: UIImage?, title: String) -> UIViewController {
        let navigationVC = UINavigationController(rootViewController: rootViewController)
        navigationVC.tabBarItem.image = image
        navigationVC.tabBarItem.title = NSLocalizedString(title, comment: "")
        rootViewController.navigationItem.title = NSLocalizedString(title, comment: "")
        return navigationVC
    }
   }
...
}

person VyacheslavB    schedule 18.08.2020    source источник
comment
Покажите, когда и где вы распределяете viewController: ViewController?.   -  person Frankenstein    schedule 18.08.2020
comment
Я делаю это в контроллере панели вкладок. Я добавил код в вопрос   -  person VyacheslavB    schedule 19.08.2020


Ответы (1)


Вы можете получить доступ к желаемому ViewController от своего rootViewController делегата в сцене. В следующем примере я считаю, что желаемый контроллер представления находится на первой вкладке контроллера панели вкладок.

if let tabbarController = self.window?.rootViewController as? UITabBarController,
   let navigationController = tabbarController.viewControllers?.first as? UINavigationController,
   let desiredController = navigationController.viewControllers.first as? ViewController {
       desiredController.someString = "some value"
}

Но, на мой взгляд, это не рекомендуемый подход, поскольку может быть много случаев, которые могут зависеть от состояния приложения или стека навигации.

Что вы можете сделать, так это добавить наблюдателя в желаемый ViewController и опубликовать уведомление от SceneDelegate следующим образом:

NotificationCenter.default.post(name: Notification.Name(rawValue: "someeventname"), object: "some value")

Вы можете добавить наблюдателя и послушать его следующим образом:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        NotificationCenter.default.addObserver(self, selector: #selector(someEventNotificationReceived(notification:)), name: Notification.Name(rawValue: "someeventname"), object: nil)
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: "someeventname"), object: nil)
    }

    @objc func someEventNotificationReceived(notification: Notification) {
        if let value = notification.object as? String {
            //handle the event here
        }
    }
}
person Muhammad Zeeshan    schedule 19.08.2020