Reputation: 401
In one of the SceneDelegate methods, I want to assign a value to a variable that is in another ViewController. How can i do this? Always getting nil. I tried different methods, but for some reason they do not work, I wanted to use the completion handler, but it seems I cannot do it in SceneDelegate methods
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
}
}
...
}
Upvotes: 2
Views: 879
Reputation: 2451
You can get access to your desired ViewController
from your rootViewController
in scene delegate. In the following example i am considering your desired view controller is in the first tab of your tab bar controller.
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"
}
But in my opinion it is not a recommended approach as there could be many cases that may depend on the application's or navigation stack's state.
What you can do is add an observer in your desired ViewController
and post a notification from the SceneDelegate
like this:
NotificationCenter.default.post(name: Notification.Name(rawValue: "someeventname"), object: "some value")
You can add and listen to the observer like this:
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
}
}
}
Upvotes: 3