Crash when trying to push view controller in Swift - ios

I am having a weird issue where my app crashes when I am trying to push a new view controller. I have set up a swipe gesture and want to segue to another view controller when a swipe is detected. When I run these 2 lines of code ...
let viewController:ViewController = ViewController()
self.navigationController?.pushViewController(viewController, animated: true)
The app crashes not specifically on either of those lines of code but rather in my ViewController class when in my viewDidLoad method I run this piece of code...
imageView.layer.masksToBounds = true
If I comment that out it crashes when I set the auto-correction type of my textField. What am I doing wrong?

First place I look when the view immediately crashes is in the Outlets for that ViewController in InterfaceBuilder. I look for anything that shows up with an exclamation mark. That usually means I renamed an outlet or broke a connection somehow. Delete anything broken by pressing the little x by the item that's messed up. I'll attach a photo so you can see.

It seems you're loading a ViewController that exists in storyboard with
let viewController:ViewController = ViewController()
which will result in nil outlets , so you have to use
let viewController = storyboard.instantiateViewController(withIdentifier: "VCID") as! ViewController
and give that vc a storyboard identifier like VCID

I think I have solved the issue but it has a weird side effect. Instead of using the line of code in #Sh_Khan's answer, I used ...
let viewController = nav?.storyboard!.instantiateViewController(withIdentifier: "mainVC") as! ViewController
The variable nav is equal to the navigation controller of the current view-controller. This seems to work without any hiccups but for some reason the back button does not disappear from the navigation controller after the segue is preformed. Does anybody know a solution to this, if so leave a comment and I will update my answer.
EDIT:
Another issue is that it wipes everything changed on that ViewController by the user clear. Is there another way to instantiate a ViewController without clearing it?

Follow what #Sh_Khan has said and in addition to that make sure that the view that you are making the push segue from is embedded in a Navigation controller.

Related

How to navigate from one storyboard to another TabBarController?

I'm trying to create an onboarding page for my Application which view is like this :
The Not Now Button supposed to navigate from this Onboarding Storyboard to ForYou Storyboard which have a storyboard that embed in navigation controller and tab bar controller.
Based on my research, i can use this line of code to make it happened
let barViewControllers = UIStoryboardSegue.init(identifier: "ForYou", source: OnboardingMasterViewController(), destination: ForYouViewController()) as! UITabBarController
let nav = barViewControllers.viewControllers![0] as! UINavigationController
let destinationViewController = nav.topViewController as! ForYouViewController
It build successfully but when i run it on simulator, the apps crash and show this line of error that i never see or learn before. The error is Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
I tried to look to google but either i used a wrong keyword or my lack of understanding, i still can't solved this error. Hope one of you can give me a guidance in finding the solution.
Thank you.
I am guessing you have already given an identifier to the Segue that I can see on the Onboarding Storyboard to ForYou Storyboard.
If not, click on that Segue in your storyboard and give its identifier.
Now, on the Not Now button's action you can do the following instead of the code that you have
performSegue(withIdentifier: "your-segue-identifier", sender: nil)
OR
You can directly connect the Segue in the storyboard from your Not Now button to ForYou storyboard, that way you won't need to write any code to achieve this.

Push Notification open specific screen in TabBarController NavigationController revealViewController

Here is what I am trying to do.
When I receive the push notification and I tap I want to show a specific screen in my app. I found a lot about it but I am having trouble due to the complexity of the structure of my application.
Here is how the app is structured:
LoginViewController
RevealViewController (https://github.com/John-Lluch/SWRevealViewController)
UITabbarController
NavigationController
ViewController (This is a table view)
DetailViewContorller
I want to pass some arguments to the DetailViewContorller so I can make sure I get the right results when opening the screen.
Here is the screenshot of my app structure
application Folow
With the following code in my AppDelegate:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tb = storyboard.instantiateViewControllerWithIdentifier("TabBarVC") as! UITabBarController
tb.selectedIndex = 1
window?.rootViewController? = tb
I have managed to get to the tabbar when tapping on the notification but I am not happy with the results. I am still having the following issues:
the revealViewController is nil so I am not able to open my setting panel
I still don't get to the DetailViewController which is at the bottom of my view hierarchy
Any hint will be appreciated.
I had a similar issue although my flow was a bit different. I ended up handling Push Notification event (when user taps on it) and storing the object at the app delegate level. In each view controller that appeared after that (in ViewDidLoad() method) I would check for that object and figure out whether to redirect the flow to the next view controller. To help with this, my notifications had a type associated with them. Unfortunately, I was not able to find a better solution.
P.S. It also appears like you're instantiating View Controllers in code and I was using Storyboards. However, the basic idea is the same. I ended
#MK_Dev, Thanks for your suggestion but I was looking for something easier to manage.
This has actually helped me.
Get top most UIViewController
Here is what I did:
if var topControl = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedContreller = topControl.presentedViewController{
topControl = presentedContreller
}
if topControl.childViewControllers[0].isKindOfClass(MyCustomClassVC) {
// Check if the user is already on the VC we are trying to open
let chatController = topControl.childViewControllers[0] as! MyCustomClassVC
// ... any additional code you need to add here ...
}
}

Swift - Elements missing when programmatically instantiating a view controller

First of all, I'm brand new to swift and iOS dev! I've decided to get started with it, and so far so good. Except for today.
So I first created a single view app, following the tuto, then I decided to see what happens if a added another view. Using segue to navigate between views seemed to work fine, so I wanted to see how I could navigate programmatically, having in mind that the "destination view" may be conditional on more than just a user pressing a button. So I added a first view to become my initial view controller, and I've found the following code online to transition to my other view:
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("home")
self.presentViewController(nextViewController, animated:false, completion:nil)
There was no problem, no error or console message, except for one little problem: some UI elements of the "destination view" (nextViewController in my case) are missing when the view loads! And some of them (but not all) show up after I click on some other elements of the view.. Note that there was/is no problem if I set the nextViewController as the initial one.
I haven't been able to find any clue on the internet about that problem, and I would greatly appreciate it if someone could point me in the right direction..
Oh well, 5 more minutes and finally an error message were enough to fix that problem!
I've found my solution on the following thread:
whose view is not in the window hierarchy
As it's said, moving my code from the viewDidLoad method to the viewDidAppear one fixed the issue. And I had the same error as the OP mentioned.

ViewController creation process using storyboard

For the following steps:
drag two view controllers using storyboard, add a button on the first VC
ctrl drag the button on the first VC to the second VC and choose present segue
embed first VC with navigation controller
My questions are:
What happens under the hood when program starts? In particular, how and where will be the first and second VC created?
If not same, what's the difference compared with code below?
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
Swift code will be preferred but Objective-C is also fine. Thanks in advance.
What you are doing using:
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
is that you are doing what the storyboard is supposed to do. You are forcefully preparing for the segue. When you simply connect the two views using the segue on the storyboard, you are telling the compiler that the connection exists. When you run the code the second viewcontroller is instantiated the instant you click on the button and performs a prepareForSegue.
All in all, its all about manually overriding the delegate methods that are called when the storyboard works.

How to initiate a viewcontroller without presenting it?

I have a tab bar controller and a few other viewcontrollers outside the tab bar controller. I have this viewcontroller called "X" which is a part of the tab bar controller. I have another viewcontroller called "Y" which is not a part of the tab bar controller. Now i want to initiate X when im inside Y upon tapping a button without actually presenting it. I want X to become active and fire its viewdidload so that i can access X whenever i chose to do so. Is this possible. Im sorry if im not clear in explaining my quiestion. let me know if you need any other additional information.
Old question at this point, but I was looking for an answer myself just yesterday and managed to get it figured out.
Instantiate the ViewController, then call loadViewIfNeeded().
Example:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleViewController") as! ExampleViewController
exampleVC.loadViewIfNeeded()
If you want, you can then check if the view is loaded with:
exampleVC.isViewLoaded
The ViewController is now all set up and ready for display when you decide to present it.
I want X to become active and fire its viewdidload so that i can access X whenever i chose to do so.
UIViewController uses lazy loading for the view property. You can just call:
[myViewController view];
This will trigger the loadView and/or viewDidLoad methods, if implemented.
However, you may wish to consider moving the relevant logic from viewDidLoad to init (or initWithCoder: if using a storyboard/xib). This way you won't have to call -view.
If I understand right, you want X to be initialised. So you can perform all you initialisation actions on your init constructor. viewDidLoad will only be called by the framework when you perform some presentation, either by pushViewController or addSubview. The reason for that is that because the framework wants to avoid getting instances of views on the memory without being used. So you can initialise all you want from your controllers but the views won't be loaded.

Resources