Swift scene userActivity NSUserActivity pass tu viewController - swift

I have a question.
in "class SceneDelegate"
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
print(url) //result is www.mywebsite.com
}
how can I pass this url to my ViewController???

It'll depend on the view controller hierarchy you have, but let's say you have a UITapBarController as your root view controller and you want to eventually get to a view controller that's within a navigation controller:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
if let windowScene = scene as? UIWindowScene {
for window in windowScene.windows {
if let rootViewController = window.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let yourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as? YourViewController,
let tabBarController = rootViewController as? UITabBarController,
let navController = tabBarController.selectedViewController as? UINavigationController {
yourVC.data = url
navController.pushViewController(yourVC, animated: true)
}
}
}
}
}
Update
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
if let windowScene = scene as? UIWindowScene {
for window in windowScene.windows {
if let rootViewController = window.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let yourVC = storyboard.instantiateViewController(withIdentifier: "EventViewController") as? EventViewController,
let navController = rootViewController as? UINavigationController {
yourVC.data = url
navController.pushViewController(yourVC, animated: true)
}
}
}
}
}

Related

Send user to a view controller from one that was made in code

I have a view controller on the storyboard that I'm trying to send the user to (TitleInfoVC), but the view controller I'm trying to send the user from was created in code, in TabBarVC, which is being set as the rootViewController in the SceneDelegate.
When I try either of the attempts in the DiscoverVC I'm getting the following error:
Attempt to present <x.TitleInfoVC: 0x12b417630> on <x.DiscoverVC: 0x12b411310> (from <xDiscoverVC: 0x12b411310>) whose view is not in the window hierarchy.
How do I send the user to the TitleInfoVC when the DiscoverVC isn't in the storyboard?
SceneDelegate:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
window?.rootViewController = TabBarVC()
window?.makeKeyAndVisible()
}
TabBarVC:
override func viewDidLoad() {
super.viewDidLoad()
let vc1 = UINavigationController(rootViewController: DiscoverVC())
let vc2 = UINavigationController(rootViewController: SearchVC())
vc1.tabBarItem.image = UIImage(systemName: "house")
vc2.tabBarItem.image = UIImage(systemName: "magnifyingglass")
vc1.title = "Discover"
vc2.title = "Search"
setViewControllers([vc1, vc2], animated: true)
}
DiscoverVC (Where I'm trying to send the user from) :
func sendToView(titleID: Int) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let titleInfoVC = storyBoard.instantiateViewController(withIdentifier: "TitleInfoVC") as! TitleInfoVC
titleInfoVC.titleID = titleID
self.present(titleInfoVC, animated: true, completion: nil)
let titleInfoVC = TitleInfoVC()
titleInfoVC.titleID = titleID
self.navigationController?.pushViewController(titleInfoVC, animated: true)
self.present(titleInfoVC, animated: true, completion: nil)
}
TitleInfoVC (Where I'm trying to send the user to) :
#IBOutlet weak var titleIDLabel: UILabel!
var titleID = 0
override func viewDidLoad() {
super.viewDidLoad()
titleIDLabel.text = "Title ID \(titleID)"
}
//EDIT:
Where sendToView is being called from (completely different view controller)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedTitleID = titles[indexPath.row].id
let discoverVC = DiscoverVC()
discoverVC.sendToView(titleID: selectedTitleID)
}
From what you show you need to work with a shared DiscoverVC.
in TabBarVC :
// use the share discoverVC
let vc1 = UINavigationController(rootViewController: DiscoverVC.shared)
in DiscoverVC declare the shared instance :
class DiscoverVC: UIViewController {
static var shared = DiscoverVC()
in TableCellVC, use the shared instance
let discoverVC = DiscoverVC.shared
discoverVC.sendToView(titleID: selectedTitleID)

Onboarding screen showing once but if user is sign in not showing maintab in swift

I am showing onboard view but i want to show once thats working othervise when user sing in i want to show main tab this code every time showing sign in screen. can you help me to solution.
Thank you
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let currentUser = Auth.auth().currentUser
let userDefaults = UserDefaults.standard.bool(forKey: "hasLaunched")
let onboardSB = UIStoryboard(name: "Onboarding", bundle: nil)
let mainSB = UIStoryboard(name: "Main", bundle: nil)
var vc: UIViewController
if userDefaults {
if currentUser != nil {
let board = UIStoryboard(name: "Main", bundle: nil)
let tabBar = board.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
window?.rootViewController = tabBar
} else {
vc = mainSB.instantiateViewController(identifier: "SignInNav")
}
}
else{
vc = onboardSB.instantiateViewController(identifier: "OnBoardingVC")
}
UserDefaults.standard.set(true, forKey: "hasLaunched")
self.window?.rootViewController = vc

Black Screen when loading View from SceneDelegate

I get an nearly black screen when I try to load this view. But if I add view.backgroundColor = .red it shows the color red correctly. Just the settings I did in Storyboard wont get shown.
Here is the code I used:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "ResultsViewController") as! ResultsViewController
window?.makeKeyAndVisible()
}
import UIKit
class ResultsViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
}
}
You seem to have created the ResultsViewController in the storyboard. You'll have to load it from the storyboard to set it as rootViewController.
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
window?.rootViewController = mainStoryboard.instantiateViewController(withIdentifier: "ResultsViewController") as! ResultsViewController
Note: Don't forget to set the identifier for ResultsViewController as "ResultsViewController" in the storyboard.

Different view controller display at start app

I try to explain situation:
I have two view controllers: viewHome and viewStartTest.
When student start app first time, don't have any data about his test in table.
In this situation should be display viewStartTest controller after launch screen.
But when he start app again and condition "test is finished" is true, viewHome controller should be display at start.
I try to put this code in AppDelegate.swift and simulate finished test but still not working, thanks for help:
// 0 - false, 1 - True
var conditionTest = 1
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if conditionTest == 1 {
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewStartTest: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewStartTest")
self.window?.rootViewController = viewStartTest
self.window?.makeKeyAndVisible()
} else {
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let ViewHome: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewHome")
self.window?.rootViewController = ViewHome
self.window?.makeKeyAndVisible()
}
}
Correct Scene delegate code after discussion below:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
if conditionTest == 1 {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewStartTest: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewStartTest")
self.window?.rootViewController = viewStartTest
self.window?.makeKeyAndVisible()
} else {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let ViewHome: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewHome")
self.window?.rootViewController = ViewHome
self.window?.makeKeyAndVisible()
}
}
guard let _ = (scene as? UIWindowScene) else { return }
}
You need to store the value of conditionTest somewhere. I would suggest using UserDefaults . This is an example of how you could implement it:
NavigationController:
class MainNavigationControllerViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
if isLoggedIn() {
let homeController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeVC")
viewControllers = [homeController]
}
}
fileprivate func isLoggedIn() -> Bool {
return UserDefaults.standard.isLoggedIn()
}
}
Extension for UserDefaults:
extension UserDefaults {
func setIsLoggedIn(value: Bool) {
set(value, forKey: "isLoggedIn")
synchronize()
}
func isLoggedIn() -> Bool {
return bool(forKey: "isLoggedIn") }
}
How to use:
with the above code you can simply login/logout the user. Make sure to call .synchronize()
Login:
UserDefaults.standard.setIsLoggedIn(value: true)
UserDefaults.standard.synchronize()
Logout:
UserDefaults.standard.setIsLoggedIn(value: false)
UserDefaults.standard.synchronize()

not getting navigationController?.pushViewController to work but present does?

I do have a non-Storyboard, 100% coded UIViewController, UICollectionView and UICollectionViewCell - works perfect.
here's the code in question:
SceneDelegate
not sure if this is relevant, tho.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let myController = MyViewController(collectionViewLayout: layout)
window?.rootViewController = myController
window?.makeKeyAndVisible()
}
.
.
ViewController
very simple and straight forward...
class MyViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let data = loadOnboardingData()
.
.
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.register(MyPageCell.self, forCellWithReuseIdentifier: "cellId")
collectionView?.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView?.tag = myPageControl.currentPage
setupMyPageControl()
}
ViewControllerExtention
here's the problem: the pushViewController method just doesn't do anything but the modal present works like a charm and I'm not getting what's wrong and why:
extension MyViewController: MyPageCellDelegate {
.
.
func didTabOnActionButton(title: String) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let homeViewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController else {
print("Coun't find controller")
return
}
navigationController?.pushViewController(homeViewController, animated: true) <- NO EFFECT
//present(homeViewController, animated: true, completion: nil) <- WORKS PERFECT!
}
MyPageCell
I set up the Delegate via protocol and it seems that's fine too
protocol MyPageCellDelegate {
func didTabOnActionButton(title: String)
}
class MyPageCell: UICollectionViewCell {
var delegate: MyPageCellDelegate?
let myActionButton: UIButton = {
let button = UIButton(type: .system)
return button
}()
myActionButton.addTarget(self, action: #selector(self.doAction), for: .touchUpInside)
.
.
#objc private func doAction(_ sende: Any) {
delegate?.didTabEndOnboardingActionButton(title: "end Onboarding")
}
so, any Idea what's wrong with:
navigationController?.pushViewController(homeViewController, animated: true)
EDIT --------------------------------------------------------------------
As pointed out by #Michcio this here: window?.rootViewController = UINavigationController(rootViewController: myController) works half way and as far as I understand it, I'm embedding myController into an UINavigationController which adds the Navigation Bar to the current and following controllers.
But that's not what I need!
What I need is a clean and simple one for the onboarding i.e. MyViewController and the HomeViewController should be one with a Tab- and Navigation Bar
Basically starting from scratch after onboarding.
I used to solve this in the previous version editing the AppDelegate first Method like this (in this example I used Storyboards):
extension AppDelegate {
func showOnboarding() {
if let window = UIApplication.shared.keyWindow, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
onboardingViewController.delegate = self
window.rootViewController = onboardingViewController
}
}
func hideOnboarding() {
if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
mainViewController.view.frame = window.bounds
UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {
window.rootViewController = mainViewController
}, completion: nil)
}
}
}
and in the Delegate itself like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let isFirstRun = true // logic to determine goes here
if isFirstRun {
showOnboarding()
}
return true
}
but I'm seriously not getting the new SceneDelegate or simply don't understand it
Really would appreciate if someone could past some code here for re-use.
It didn't work, because you are set MyViewController as window.rootViewController. Just change line in SceneDelegate to:
window?.rootViewController = UINavigationController(rootViewController: myController)