navigationController unexpectedly found nil on Swift - ios

I am facing very weird error unexpectedly found nil while unwrapping an optional value navigationcontroller.
I have two viewControllers which has main function is to scan bar code and sets value in textField on PreBarCodeViewController. Second viewController is the barcodeViewController which scan. According to perspective user either manually input value or scan to fetch bar code. When I go for manual input navigation controller works fine. But once I click for scan and gets value in a textField and press ok button it won't navigate. Even if I click cross button it gives me nil error.
Updated: included barcode viewcontroller open on button tap.
PreBarcodeViewController: two buttons Back and Accept
#IBAction func toBarcode(_ sender: Any) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "BarcodeViewController") as! BarcodeViewController
present(newViewController, animated: true, completion: nil)
}
#IBAction func onClickedBackArrow(_ sender: Any) {
self.navigationController!.popViewController(animated: true)
}
#IBAction func onClickedAccept(_ sender: Any) {
let value = textField.text ?? String(describing: txtValue)
bardelegate?.listFunc(listValue: value )
self.navigationController?.popViewController(animated: true)
}
BarcodeViewController: When I get the value post to back.
if url == decodedURL {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "PreBarcodeViewController") as! PreBarcodeViewController
let str2 = String(url)
newViewController.txtValue = str2
present(newViewController, animated: true, completion: nil)
}

When you open with present() view controller then used the
dismiss()
method to back to previous screen.
popViewController()
only used when you navigate with navigation controller please check this.

Related

Why I get a uncaught expetion when I want save a value

I'm just learning XCode and now I have the following problem, I've tried a few things but I can't get any further at this point, does anyone have an idea of what this could be.
I have two ViewControllers. With the first ViewController you have the possibility to open a popup for user input via a button (second ViewControler). After entering the user, you can save the user with a save button and you should get back to the main page. Then I always get the error
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PwGen.ViewControllerUser tfUser:]: unrecognized selector sent to instance "
///////////////////////////Button save
#IBAction func btnConfirm(_ sender: UIButton)
{
save()
let story = UIStoryboard(name: "Main", bundle: nil)
let controller = story.instantiateViewController(withIdentifier: "ViewController") as! ViewController
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: false, completion: nil)
}
///////////////////////////function save
func save()
{
let strEingabe = tfUser.text
let defaults = UserDefaults.standard
defaults.set(strEingabe, forKey: "customTextUser")
defaults.synchronize()
let strtest = defaults.string(forKey: "customTextUser")
print(strtest)
}
Thanks a lot
Hi guys,
I've tried a few more things, but without success
Here is the code of my second ViewControll. If I don't enter anything in the "tfUser" text field, everything works as desired and the first view controller is opened and the code of the first view is processed. However, if you enter something in "tfUser", the value is saved, the first ViewController is opened and then crashes, although the same code is processed as if you left "tfUser" empty
i don't know why its working when "tfUser" is empty to and string in "tfUser".
import UIKit
class ViewControllerUser: UIViewController {
#IBOutlet weak var tfUser: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//Button abort
#IBAction func btnBack(_ sender: UIButton)
{
tfUser.text = ""
let vc = storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
vc.modalPresentationStyle = .fullScreen
present(vc, animated: false)
}
//Button confirm
#IBAction func btnConfirm(_ sender: UIButton)
{
save()
let vc = storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
vc.modalPresentationStyle = .fullScreen
present(vc, animated: false)
}
//function save
func save()
{
let strEingabe = ("\(tfUser.text ?? "")")
let defaults = UserDefaults.standard
defaults.set(strEingabe, forKey: "customTextUser")
tfUser.text = ""
}
}

SWIFT: Navigate to UIViewControllers from single function with a variable

I'm trying to make a function for my navigation without having to type the exact same lines over and over again.
Trying to do so results into an error: "Use of undeclared type 'viewController'"
Am I doing this completely wrong, should I just place these 4 lines on every button just with different identifier and viewController?
func navigateTo(identifier:String, viewController:UIViewController) {
let newVC = storyboard?.instantiateViewController(withIdentifier: identifier) as! viewController
newVC.modalPresentationStyle = .fullScreen
newVC.modalTransitionStyle = .flipHorizontal
self.present(newVC, animated: true, completion: nil)
}
#IBAction func btnOneTapped(_ sender: Any) {
navigateTo("myVC", MyViewController)
}
Make sure you provide correct identifier...below code works perfectly.
Your Error -> Trying to do so results into an error: "Use of undeclared type 'viewController'"
In this there is a typo mistake for ViewController i.e you are trying this - viewController
Also always try to do Optional-Binding instead to force-unwarpping it may cause crash in your app.
func navigateTo(identifier:String, viewController:UIViewController) {
if let newVC = storyboard?.instantiateViewController(withIdentifier: identifier) {
newVC.modalPresentationStyle = .fullScreen
newVC.modalTransitionStyle = .flipHorizontal
self.present(newVC, animated: true, completion: nil)
}
}
#IBAction func confirmBtn(_ sender: UIButton) {
navigateTo(identifier: "myVC", viewController: MyViewController())
}
You are passing an instance of UIViewController and trying to cast the UIViewController to it in the next line. Modify your function to take in ViewController.Type as parameter like this:
func navigateTo<ViewController: UIViewController>(identifier: String, viewController: ViewController.Type) {
let newVC = storyboard?.instantiateViewController(withIdentifier: identifier) as! ViewController
newVC.modalPresentationStyle = .fullScreen
newVC.modalTransitionStyle = .flipHorizontal
self.present(newVC, animated: true, completion: nil)
}
#IBAction func btnOneTapped(_ sender: Any) {
navigateTo(identifier: "myVC", viewController: MyViewController.self)
}
Thank you guys, I've got it working like so:
func navigateToVC(identifier:String, viewController:ViewController.Type) {
let newVC = storyboard?.instantiateViewController(withIdentifier: identifier) as! ViewController
newVC.modalPresentationStyle = .fullScreen
newVC.modalTransitionStyle = .flipHorizontal
self.present(newVC, animated: true, completion: nil)
}
#IBAction func btnOneTapped(_ sender:Any) {
navigateToVC(identifier: "myVC", viewController: MyViewController.self)
}

Swift 4 – Custom Alerts with protocols

I'm having issues with Custom alerts and sending actions back to VC from which alert was called.
I have two classes:
Factory
ConfirmationAllert
User journey I'm trying to achieve:
The user performs actions in the Factory class after he finishes I call ConfirmationAllert using such code:
func showAlert() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "ConfirmationAllert")
myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
(view as? UIViewController)?.present(myAlert, animated: true, completion: nil)
}
In ConfirmationAllert class I have button, which:
dismisses alert
sends action to Factory - this action is to dismiss Factory VC and go back to previous VC.
First action completes successfully, the second action not working. I'm using protocols to send the second action to Factory VC, but something is not working, and I don't know what.
Here is my code:
Factory
final class FactoryViewController: UIViewController {
let alert = ConfirmationAllert()
#IBAction func didPressSave(_ sender: UIButton) {
showAlert()
}
func goToPreviousVc() {
alert.delegate = self
print("Inside factory") -> print don't get called
// navigationController?.popViewController(animated: true) -> none of this works
// dismiss(animated: true, completion: nil) -> none of this works
}
}
extension FactoryViewController: ConfirmationAllertDelegate {
func dismissVC() {
goToPreviousVc()
print("Go to previous")
}
}
ConfirmationAllert
protocol ConfirmationAllertDelegate {
func dismissVC()
}
class ConfirmationAllert: UIViewController {
var delegate: ConfirmationAllertDelegate?
#IBAction func didPressOk(_ sender: UIButton) {
self.delegate?.dismissVC()
}
}
I didn't include viewDidLoad methods as I'm not calling anything there.
My issue is that method goToPreviousVc() doesn't perform any actions.
Thank you in advance for your help!
I guess your problem is that you setup your ConfirmationAllertDelegate at goToPreviousVc that supposed to be called using that delegate.
Instead, try to set up you delegate when you creating myAlert object
let myAlert = storyboard.instantiateViewController(withIdentifier: "ConfirmationAllert")
(myAlert as? ConfirmationAllert).delegate = self
// the rest of your code
After that, your alert will have a delegate since it was created and when you press the button, it should work as you expect.
Try to use below code
func showAlert() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myAlert = storyboard.instantiateViewController(withIdentifier: "ConfirmationAllert") as! ConfirmationAllert
myAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
myAlert.delegate = self
present(myAlert, animated: true, completion: nil)
}

Swift 3 - Close current ViewController and Open new ViewController

I've gone through a tad amount of SO posts about this but none of them clearly state how to get this done in Swift 3.
Simply put, I need to close the current view that is displayed and open a new view controller. Such that the only view controller open would be the 2nd VC
This is the code I tried using, but when I try this the view controller gets closed without the rest of the code getting executed
//Close current VC
self.dismiss(animated: true, completion: nil)
//Open the new VC
let mainStoryboard: UIStoryboard = UIStoryboard(name:"Main",bundle:Bundle.main)
let secondViewController: SecondViewController = mainStoryboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.present(secondViewController, animated: true, completion: nil)
Can someone help me out? I just need a simple transition from 1st VC to 2nd VC and close the 1st VC.
The problem is, that "self" can not present the new ViewController since it is the ViewController that is getting dismissed.
You could try calling self.presentingViewController?.present(secondViewController, animated: true, completion: nil)
After spend full day i got a solution on Apple' developer website (on this link)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewController(identifier: "second_view_controller")
secondVC.modalPresentationStyle = .fullScreen
secondVC.modalTransitionStyle = .crossDissolve
present(secondVC, animated: true, completion: nil)
If you presented that view controller from some view controller or it is the viewcontroller from navigation or tab viewcontroller, then try to get last visible view controller, code is in this link
Get the current displaying UIViewController on the screen in AppDelegate.m
or else use this code (I have copied from that link)
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
Then present your viewcontroller from that visibleViewController -
//Close current VC
self.dismiss(animated: true, completion: nil)
//Open the new VC
let mainStoryboard: UIStoryboard = UIStoryboard(name:"Main",bundle:Bundle.main)
let secondViewController: SecondViewController = mainStoryboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
window?.visibleViewController?.present(secondViewController, animated: true, completion: nil)
If your view controller is the root view controller, then set it to root view controller
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.window?.rootViewController = secondViewController
}

Swift - Warning: Attempt to present * on * while a presentation is in progress

I can't switch to another view controller because of this error. I want to switch to another view controller after it successfully scan the QR code.
2015-01-27 17:59:16.093 *[5416:1860144] Warning: Attempt to present <*.SuccessViewController: 0x144e38a20> on <*.MethodViewController: 0x144e2b960> whose view is not in the window hierarchy!
My code
#IBAction func btnQrCode(sender: AnyObject) {
reader.modalPresentationStyle = .FormSheet
reader.delegate = self
reader.completionBlock = { (result: String?) in
if result != nil {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let successViewController = storyBoard.instantiateViewControllerWithIdentifier("successView") as SuccessViewController
self.presentViewController(successViewController, animated:true, completion:nil)
}
presentViewController(reader, animated: true, completion: nil)
}
}
P.S: I'm using QRCodeReader plugin, https://github.com/yannickl/QRCodeReader.swift.
Can you try showing the modal view controller after the reader(QRCodeReader) has been dismissed. There is a callback for QRCodeReader called didScanResult in the documentation.
https://github.com/yannickl/QRCodeReader.swift
func reader(reader: QRCodeReader, didScanResult result: String) {
self.dismissViewControllerAnimated(true, completion: { () -> Void in
// use the result variable here.
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let successViewController = storyBoard.instantiateViewControllerWithIdentifier("successView") as SuccessViewController
self.presentViewController(successViewController, animated:true, completion:nil)
})
}
Remove the code from reader.completionBlock.

Resources