SWIFT: Navigate to UIViewControllers from single function with a variable - ios

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)
}

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 = ""
}
}

How to pass UIVIewController name as a parameter to particular function using swift?

In my scenario, I need to pass UIVIewController name and some more string values to particular function. I tried below code but not getting result.
Passing Parameters To Particular Function
self.accountoptionscall(vcName: UIViewController(), vcIdentifier: "profileviewcontroller", popUpVC: ProfileViewController.self)
func accountoptionscall<T: UIViewController>(vcName: UIViewController,vcIdentifier: String, popUpVC: T.self) {
let viewcontrollers = self.storyboard!.instantiateViewController(withIdentifier: vcIdentifier) as! vcName
let navController = UINavigationController(rootViewController: viewcontrollers)
self.present(navController, animated:true, completion: nil)
}
I use it in my app, I think it can help you.
extension UIViewController {
/// Load UIViewController type from UIStoryboard
class func loadFromStoryboard<T: UIViewController>() -> T {
let name = String(describing: T.self)
let storybord = UIStoryboard(name: name, bundle: nil)
if let viewController = storybord.instantiateInitialViewController() as? T {
return viewController
} else {
fatalError("Error: No initial view controller in \(name) storyboard!")
}
}
}
Here how you can use it:
func loadVC<T: UIViewController>(controller: T) {
let vc: T = T.loadFromStoryboard()
let navigationVC = UINavigationController(rootViewController: vc)
self.present(navController, animated:true, completion: nil)
// or if use in appDelegate you can do it: window?.rootViewController = navigationVC
}

nil Delegate between two ViewController with two different Bundle (swift)

nil Delegate between two ViewController with two different Bundle using swift 4 (commented in second code)
here is my code :
First ViewController :
class FirstVC : UIViewController, MerchantResultObserver{
var secVC = SecondVC()
override func viewDidLoad() {
secVC.delegate = self
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
let controller = storyboard.instantiateInitialViewController()
self.present(controller!, animated: true, completion: nil)
secVC.initSecondVC(data)
}
func Error(data: String) {
print("-------------Error Returned------------- \(data)")
}
func Response(data: String) {
print("-------------Response Returned------------- \(data)")
}
}
Second ViewController :
public class SecondVC: UIViewController {
public weak var delegate: MerchantResultObserver!
public func initSecondVC(_ data : String){
print(data)
}
#IBAction func sendRequest(_ sender: UIButton) {
delegate?.Response(data: “dataReturnedSuccessfully”) // delegate is nil //
dismiss(animated: true, completion: nil) // returned to FirstVC without returning “dataReturnedSuccessfully” //
}
}
public protocol MerchantResultObserver: class{
func Response(data : String)
func Error(data : String)
}
Any help would be appreciated
var secVC = SecondVC()
and
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
let controller = storyboard.instantiateInitialViewController() as? SecondVC
These both are different instances.
You can assign a delegate to the controller, like
controller.delegate = self
It will call the implemented delegate methods in First View Controller.
Full Code.
let storyboard = UIStoryboard(name: “SecondVC”, bundle: Bundle(identifier: “SecondBundle”))
if let controller = storyboard.instantiateInitialViewController() as? SecondVC {
//Assign Delegate
controller.delegate = self
//It's not init, but an assignment only, as per your code.
controller.initSecondVC(data)
self.present(controller, animated: true, completion: nil)
}
One more thing, Don't present View in ViewDidLoad. You can put a code in some button or in a delay method.

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)
}

Dismiss view controller to previous view controller

I know lots of people may asked this question . i have also find the solution but i am not able to understand what is wrong in my code ?
popcontroller.swift:
protocol DataSendDelegate {
func sendgetattid(pop_att_id: Int, pop_in_time: String)
}
var delegate: DataSendDelegate? = nil
if statuss == "200" {
let send_pop_att_id = att_id
let send_pop_in_time = in_time
self.navigationController?.popViewController(animated: true)
self.dismiss(animated: true) {
self.delegate?.sendgetattid(pop_att_id: send_pop_att_id, pop_in_time: send_pop_in_time)
}
}
In the above code i get the correct value but it does not dismiss and go to next view controller .
attendanceViewController.swift:
class attendanceViewController: UIViewController , DataSendDelegate {
func sendgetattid(pop_att_id: Int, pop_in_time: String) {
DispatchQueue.main.async {
self.inTimeTextField.text = pop_in_time
self.get_att_id = pop_att_id
self.in_time_button.isEnabled = false
self.out_time_button.isEnabled = true
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let popVC = segue.destination as? PopUpViewController
{
popVC.popEmailID = att_emp_id
popVC.delegate = self
}
}
}
Update from your comment:
You didn't present viewController. You have pushed some view controller. So Just pop it. discard the dismiss
self.delegate?.sendgetattid(pop_att_id: send_pop_att_id, pop_in_time: send_pop_in_time)
self.navigationController?.popViewController(animated: true)
If you did self.present(ViewController, animated: true, completion: nil) from the previous ViewController to show the current viewcontroller, you must do
self.dismiss(animated: true) {
self.delegate?.sendgetattid(pop_att_id: send_pop_att_id, pop_in_time: send_pop_in_time)
}
or if you did self.navigationController?.pushViewController(ViewController, animated: true) you must do self.navigationController?.popViewController(animated: true)

Resources