instantiateViewController with the UINavigationController it is embedded in - swift

I'm opening a VC upon a reception of local notification.
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
application.applicationIconBadgeNumber = 0
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var VC = storyboard.instantiateViewControllerWithIdentifier("PendingRequest") as! PendingRequestVC
let navController = UINavigationController.self(rootViewController: VC)
UIApplication.sharedApplication().keyWindow!.rootViewController = navController
}
The PendingRequestVC that appears has a programmatically Close Tab Item that can't be used with the navController that I created in the code above.
I've tried to insert the Tab Item from the Storyboard and used the Presented Segue instead but I'm still unable to close my PendingRequestVC.
How can I call PendingRequestVC with the NavController it's Embed in instead of creating a new one?
Or how can I close my PendingRequestVC with the created NavController?
Thanks in advance

Why you set the rootViewController of the keyWindow? You may need to presenting a modal view controller:
let rootViewController = UIApplication.sharedApplication().keyWindow!.rootViewController
rootViewController.presentViewController(navController, animated: false, completion: nil)
When you want to close the PendingRequestVC with the created NavController:
// PendingRequestVC
self.dismissViewControllerAnimated(true, completion: {});

Related

Whose view is not in the window hierarchy only in First Launch

I have an Onboarding screen that I'm showing to the new users when they first open the app.
In my appDelegate I check whether is the first launch or not.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var initialViewController = storyboard.instantiateViewController(withIdentifier: "OnBoarding")
let userDefaults = UserDefaults.standard
if userDefaults.bool(forKey: "onBoardingComplete") {
initialViewController = storyboard.instantiateViewController(withIdentifier: "MainApp")
}
window?.rootViewController = initialViewController
window?.makeKeyAndVisible()
}
Also I have a collectionViewCell that I have some buttons and when I click them I get an Alert with informations.
Example of one button
#IBAction func guide3Btn(_ sender: Any) {
let infoVC = infoService.info(title: "Title", body: "Information")
self.window?.rootViewController?.present(infoVC, animated: true, completion: nil)
}
When the user first launches the app if he clicks the info button gets this:
Warning: Attempt to present <MyApp.InfoViewController: 0x7f91db45cfb0> on <MyApp.OnbBoardViewController: 0x7f91db506af0> whose view is not in the window hierarchy!
If the user reopens the app everything is ok. I know that when we have first launch we have onBoarding as root controller but I can't understand how to fix this.
Update
This is the infoService class. I use a new storyboard to create the alert.
class InfoService {
func info(title: String, body: String) -> InfoViewController {
let storyboard = UIStoryboard(name: "InfoStoryboard", bundle: .main)
let infoVC = storyboard.instantiateViewController(withIdentifier: "InfoVC") as! InfoViewController
infoVC.infoBody = body
infoVC.infoTitle = title
return infoVC
}
}
You can try add your storyboard instantiate code blocks to main thread using DispatchQueue.main.async like below:
I solved almost all of my whose view is not in the window hierarchy! problems.
DispatchQueue.main.async {
let infoVC = storyboard.instantiateViewController(withIdentifier: "InfoVC") as! InfoViewController
infoVC.infoBody = body
infoVC.infoTitle = title
}
return infoVC
Referenced from : https://stackoverflow.com/a/45126338/4442254

Swift - How switch between storyboards with back button?

I'm in a storyboard and I need to go to another storyboard by tapping a button. Well, this I've already done, but I need to go back to previous storyboard. Here is my code:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
}
By tapping a button on my UITableViewCell (where I have a protocol), this function (goContact) is called and I switch to another storyboard (FAQ). But, how can I go back to main.storyboard?
I've already tried do this too:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
// self.navigationController?.pushViewController(vc, animated: true)
// self.present(vc, animated: true, completion: nil)
}
Use only storyboard property , it references to Main storyboard of the app or you can write it like let storyboard = UIStoryboard(name: "Main", bundle: nil)
To go back after push do
self.navigationController?.popViewController(animated: true)
You should push your new view controller onto the navigation controller using push, like in your commented-out code. That will cause the new view controller to have a back button, which will pop it for you without needing any extra code.

Push to ViewController from AppDelegate with stack and navigation Bar

I'm developing a messaging app and I'm having trouble implementing push notification behaviour.
What I want is that when a user taps on the notification, the conversation of that group opens. But there has to be a Navigation bar to go back to the list of contacts.
I already know how to extract information from the notification to get the contact name. I'm trying this in the function didReceive on AppDelegate.
So far what I've tried is:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ChatViewController") as! ChatViewController
vc.contactName = name as String
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
self.window?.makeKeyandVisible()
This open the right conversation and the messages appear, but UI elements are no responsive (can't write when tapping textfield, cant navigate to gallery when tapping button, etc.) and also there is no Navigation bar.
So after doing some research, I've tried this:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ChatViewController") as! ChatViewController
vc.contactName = name as String
let rootViewController = self.window?rootViewController as! UINavigationController
rootViewController. pushViewController(vc, animated: true)
This doesn't work. There is no error message but the screen is just white.
This is my Storyboard:
I'm using SWRevealViewController for the side menu and the messaging part has a tabBarController, with the contact list on the 2ยบ tab.
EDIT: With the second method, there is an error.
Could not cast value of type 'SWRevealViewController to UINavigationController'
I think you should go with NotificationCenter to do this.
When the user click on the notification you should post a NotificationCenter in the didReceive like this:
NotificationCenter.default.post(name: .onMessageRecieved, object: notificationObject)
And based on which view controller you're in you should add an observer there in the viewDidLoad() func so it understands a message has been recieved like this:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.onMessageRecieved(notification:)), name: .onMessageRecieved, object: nil)
}
And you should have a func (onMessageRecieved) in the view controller to do the navigation like this:
func onMessageRecieved(notification: NSNotification){
// open the conversation
let vc = self.storyboard?.instantiateViewController(withIdentifier: "ChatViewController") as! ChatViewController
vc.contactName = name as String
self.navigationController?.pushViewController(vc, animated: true)
}
This way you are doing the navigation from the view controller so the navigation will be there as well.
Could not cast the value of type 'SWRevealViewController to UINavigationController'
This issue is because of the "SWRevealViewController" is not a subclass of UINavigationController. So you can't cast it this way.
To solve the chat ViewController issue, you should modify your code like this.
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ChatViewController") as! ChatViewController
let nav = vc.navigationController
vc.contactName = name as String
let rootViewController = self.window?rootViewController as! UIViewController
rootViewController.presentViewController(nav, animated: true, completion: nil)
But the chat VC will be in the presenter mode. You should handle the dismiss.
You just try this and let me know is it working or not.

How to reset/restart viewcontroller in Swift?

I want to have a button on my navigation bar "Reset" and I would like this to be connected to an IBAction to sort of "restart" the controller.
I have some segues from another controller that changes some aspects of the viewcontroller (that has a collectionview) and I want the user to be able to start over. Does anyone have any suggestions as to how to proceed?
If you embed navigation controller to your view controller then you can use this code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController")
let viewcontrollers = self.navigationController.viewControllers
viewcontrollers.removeLast()
viewcontrollers.append(vc)
self.navigationControllers?.setViewControllers(viewcontrollers, animate: true)
You can change rootViewController of your application:
UIApplication.shared.keyWindow?.rootViewController = UIViewController()
This is how I do it in Swift 2.1 with my Home view inside a UINavigationController:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let homeVC = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
self.navigationController?.presentViewController(homeVC, animated: false, completion: nil)
self.navigationController?.dismissViewControllerAnimated(false, completion: nil)

Presenting a a ViewController on a xib file in SWIFT

I have a xib file which I have created a pop up controller on a UIView. This pop up controller animates up when a button is pressed on a View Controller 1. I then have a button on the UIView which when pressed I want to present another View Controller (View Controller 2). code looks like:
class PopUpViewControllerSwift : UIViewController {
#IBAction func goToVC2(sender: UIButton) {
self.removeAnimate()
let VC2: VC2 = self.storyboard?.instantiateViewControllerWithIdentifier("VC2") as VC2
var modalStyle: UIModalTransitionStyle = UIModalTransitionStyle.CoverVertical
VC2.modalTransitionStyle = modalStyle
presentViewController(VC2, animated: true, completion: nil)
}
}
Although thou when the button is pressed it crashes, no error or callbacks or anything. Obviously this would normally work if it was just a regular View Controller but because I am doing it inside a pop Up View which has been animated on top of another View I think that is the problem?
Can anybody help?
thanks
I did this in a UICollectionView didSelectItemAtIndexPath method.
// Register Nib
let newViewController = NewViewController(nibName: "NewViewController", bundle: nil)
// Present View "Modally"
self.present(newViewController, animated: true, completion: nil)
I set the ID of the ViewController to the same as the file name so I would be sure to reference the right ViewController.
Make sure self.storyboard is not nil.
Also confirm that VC2 is one of the ViewController's identity in the storyboard file.
I hope it could help you.
if VC2 is in a storyboard file, try to use following command to get VC2
let storyboard = UIStoryboard(name: "YourStoryboardName(maybe 'Main')", bundle: nil)
let vc2 = storyboard.instantiateViewControllerWithIdentifier("VC2") as VC2
or if VC2 is in a nib file, try to use following command to get VC2
let vc2 = VC2(nibName: "YourNibName", bundle: nil)
It should be like this:
let vc = MyViewController(nibName: "MyViewController", bundle: nil)
present(vc, animated: true, completion: nil)