now I am developing messenger
MessengerBox is tableViewController, when user tap the one of the cell, then chatRoomViewcontroller is presented.
if the app is not running and message arrived, then push notifications show. And user Tap the notification, App shows chatRoomViewcontroller directly.
Initially, I implemented this code by using window.rootViewController
But the problem happened. when I tap Back Button of chatRoomviewController, change is not happened because this view controller is rootview and its presentingViewController is empty!
so I fixed it like below
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
///some code for notification..
let mVC //this is MessengerBoxViewcontroller
let crVC //this is ChatRoomViewController
CRVC?.sender = "asdf"
do{
self.window?.rootViewController = mVC
self.window?.makeKeyAndVisible()
defer{
mVC?.presentChatRoomVC()
}
}
/// some code...
}
It works! But I'd like to know better way.
And Also I think I should study How window and viewcontrollers works.
please recommend me the better way, and reference documents.
Thank you.
You need to handle back button action programatically in ChatRoomViewControllerto solve your problem :
On back button Click :
Check for MessengerBoxViewcontroller is present in navigationController stack.
if MessengerBoxViewcontroller is in navigationController stack then pop to move back to MessengerBoxViewcontroller.
Else present MessengerBoxViewcontroller.
if let viewControllers = self.navigationController?.viewControllers {
for viewController in viewControllers {
if viewController.isKindOfClass(MessengerBoxViewcontroller) {
print("Your controller exist")
navigationController?.popViewController(animated: true)
}
}
}
else {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "messengerBoxViewcontroller") as! MessengerBoxViewcontroller
self.present(vc, animated: true, completion: nil)
}
Related
I want to pop current view controller on some condition from appDelegate but I don't know how to do so, if any idea please help me out...................................................................................
import UIKit
import IQKeyboardManagerSwift
let kSharedAppDelegate = UIApplication.shared.delegate as? AppDelegate
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.window = UIWindow(frame: UIScreen.main.bounds)
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enableAutoToolbar = false
//IQKeyboardManager.shared.toolbarTintColor = .white
//IQKeyboardManager.shared.toolbarBarTintColor = ColorSet.appTheamColor
kSharedAppDelegate?.moveToSplashVC()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Check we can access the application window
guard let window = UIApplication.shared.windows.first else {
return
}
// Check we can access the root viewController
guard let vc = window.rootViewController else {
return
}
// Check the root vc is the type that we want to dismiss
if vc is NoInternetPopUpViewController {
vc.dismiss(animated: true, completion: nil)
}
}
//MARK:- Show No Internet connection VC
func showNoInterNetVC() {
guard let controller = UIStoryboard(name: Storyboards.kNoInternet, bundle: nil).instantiateViewController(withIdentifier: Identifiers.kNoInternetPopUpViewController) as? NoInternetPopUpViewController else {return}
controller.modalPresentationStyle = .overFullScreen
controller.modalTransitionStyle = .crossDissolve
kSharedAppDelegate?.window?.rootViewController?.present(controller, animated: true, completion: nil)
//window.present(controller , animated: true)
}
}
I think pop is the wrong terminology here unless you are using a navigation controller.
If you want to dismiss the currently presented viewController you could check the rootViewController of the applications Window like this.
// Check we can access the application window
guard let window = UIApplication.shared.windows.first else {
return
}
// Check we can access the root viewController
guard let vc = window.rootViewController else {
return
}
// Check the root vc is the type that we want to dismiss
if vc is NoInternetPopUpViewController {
vc.dismiss(animated: true, completion: nil)
}
I also just noticed that you may not need to access the application singleton via the shared property, as applicationDidBecomeActive(_ application: UIApplication) is passing you the Application already - that line would become:
guard let window = application.windows.first else {
There is another way to do this, in newer iOS versions you directly have access to topViewController() so you access it like UIApplication.topViewController() the only downside of it is that you need yo wrap it into an if let statement to check if it is not null. FYI, It won’t be null in most cases if you have let your didFinishLaunching() method run at least once in your app delegate. So that it can stack a view controller to be a top view controller. This won’t be a problem for you since all of the other methods will fail as well if this is the case.
Todo a pop view controller now all you need to do it use top view controller and perform pop on its navigation view controller, or you can dismiss it in case there is no navigation view controller.
I have a situation where if the user is not logged in to Firebase, when they launch my app, a modal viewcontroller is presented asking them to log in.
I am also using UIActivityViewController to send data between devices, but want to notify the user with an alert if he is not logged in.
I figure I can do this from the AppDelegate in the open url application function:
func application(_ app: UIApplication, open url: URL, ...
I just have to figure out how to navigate to that viewcontroller to call the function that will present my alert.
Within this function, I have this:
if status == .notLoggedIn {
guard
let rootVC = window?.rootViewController as? UITabBarController,
let collectionSplitVC = rootVC.viewControllers?.first as? UISplitViewController,
let navVC = collectionSplitVC.viewControllers.first as? UINavigationController,
let MyBookshelfCollectionVC = navVC.children.first as? MyBookshelfCollectionVC
// here is where I want to get access to the modal viewController presented on this MyBookshelfCollectionVC.
// it is called LoginVC
else { return true }
LoginVC.showAlertFromAppDelegate(status: status)
}
So the question his, how do I access this modal viewcontroller?
I got some logic I want to do in my LaunchScreen, and if the check is alright, I want to segue to a viewController and if not I want to segue to another, is that possible?
I got some logic I want to do in my LaunchScreen
Now that I understand the question, I can answer it: don't. Do your time-consuming logic later. Your job is to launch fast. You need to get out of applicationDidFinishLaunchingWithOptions, get out of viewDidLoad, and launch.
What you show at that point is up to you; if you have time-consuming stuff (in your case, it sounds like you're networking or doing something else that takes time while you load up the data source for a table) and you want to show a special view controller that covers the time with a spinning activity view or something, fine. But during actual launch is not the time to do that.
No you cant code for launchScreen.Storyboard, The reason why :- when your launchScreen.storyboard shows the app is still loading.
Simply put: You cant access your app when it is displaying launchScreen.storyboard, all you can do is make a UI/UX for that not execute any code for it.
Alternative:- Make a viewController that appears as a first viewController check your logic there and do things from there accordingly!
Reference : - https://stackoverflow.com/a/27642160/6297658
Your LaunchScreen is shown while your app is loading. Go to your AppDelgate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
window.rootViewController = //your root view controller that you have figured out with logic
return true
}
Run your check in didFinishLaunchingWithOptions() and use that to "jump" directly to a specific vc. Here's an example using userDefaults, but of course you can replace that with whatever check you're running.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Do some logic
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let welcomeVC = storyboard.instantiateViewControllerWithIdentifier("WelcomeNavController")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = welcomeVC
self.window?.makeKeyAndVisible()
}
}
Add this function into the AppDelegate:
func initialVC(storyboardID: String) {
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController : UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("\(storyboardID)") as UIViewController
self.window?.makeKeyAndVisible()
if storyboardID == "tabBarVC" {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = initialViewController
} else {
let navController = UINavigationController(rootViewController: initialViewController)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = navController
}
}
In the didFinishLaunchingWithOptions method inside of the AppDelegate, you can add this:
if currentUser != nil {
initialVC("tabBarVC")
} else {
initialVC("loginVC")
}
You can see in my example, I am either loading the main app VC or the Login VC depending on if the user is logged in. In your case, You can use an if - else statement and do the logic within the initialVC function.
Note: When I call for the loginVC to be loaded, I have to load the navigationController because the loginVC is embedded in a navigationController. For the tabBarVC, I don't embed the navController because it isn't needed.
I am working on an app that has two Storyboards: One for my app's onboarding controllers and the other for my main app. My onboarding view controller has a skip button that when pressed directs the user to the main storyboard. I only want to show the onboarding view as long as the user hasn't hit the skip button. Once the skip button is hit, the corresponding storyboard should disappear forever.
I thought I could fix this problem by only making showing onboarding storyboard when the app is first opened, and I found some code online that seemed helpful, however it doesn't work...here is the code that is in my app's AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
FIRApp.configure()
Fabric.with([Crashlytics.self])
let defaults = NSUserDefaults.standardUserDefaults()
if (defaults.objectForKey("userAsLoggedInBefore") != nil) {
print("Functions")
//here you insert the code to go to the main screen
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "Functions", bundle: nil)
let viewcontroller : UIViewController = mainView.instantiateViewControllerWithIdentifier("functions") as UIViewController
self.window!.rootViewController = viewcontroller
} else {
//this means the user hasn't logged in before and you can redirect him to the onboarding page
print("Onboarding")
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "Main", bundle: nil)
let viewcontroller : UIViewController = mainView.instantiateViewControllerWithIdentifier("onboarding") as UIViewController
self.window!.rootViewController = viewcontroller
}
}
Note in my code "Main" is the onboarding storyboard, while "Functions" is my main app code.
However this code is not working as intended as my same problem still arises. If anybody could take a look at my code and see if I am doing anything wrong, that would be greatly appreciated.
Thanks in advance!
You are never writing to NSUser defaults. So it will stay nil..
Your missing some line like this:
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setValue("Did watch", forKey: "userAsLoggedInBefore")
Put it at the end of if - else statement
I have a Swift application, and what I'd like to do is that every time the app becomes active, I'd like to check for a user in session. If not found, I'd like to show a login view controller that I designed in my Storyboard. If found, I need everything to just resume as usual.
Where is the best way to trigger this check? Is AppDelegate's applicationDidBecomeActive the right place for this?
If yes, how do I actually instantiate the login view controller and show it? I have another home view controller, which is set to be my initial view controller. How do I manage this controller if and when I do end up successfully pushing the login view controller from the app delegate in case there is no user found in session? I don't want the home view controller to show up if a user is not found.
Any advise is greatly appreciated!
Hope this answer can help!
Put this in your AppDelegate.swift file. With the if you can check the value saved in local memory.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var userLoggedIn: Bool = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if (userLoggedIn){
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var homeViewController = mainStoryboard.instantiateViewControllerWithIdentifier("HomeViewController") as!
HomeViewController
window!.rootViewController = homeViewController
}
return true
}
If let's say you store a token in your usersession, we go look if there is a token set or not. If it's already set (so not null) then we go to your other viewcontroller
let prefs = NSUserDefaults.standardUserDefaults()
let checkfortoken = prefs.stringForKey("token")
if(checkfortoken != ""){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("identifierofyourview") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
Now you want to check this when you start your app so we gonna put the code into appdelegate in the first function (didFinishLaunchingWithOptions):
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
//so here ...
return true
}