Lets say I have 2 ViewControllers, in my MainViewController I have a button which performs a segue to SecondViewController. When button tapped, I'm saving some initial data to coreData, so it takes some time.
Here is the thing that I want to do;
While passing between ViewControllers, I want to show ActivityIndicator, but its starts after SecondViewController is opened. Could you help me? I'm new to Swift.
Here is the code I used in my MainVC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "SecondViewController") {
SwiftSpinner.show("Loading") // Act. indicator found on github
willRunOnce() // Here Im saving data to CoreData
SwiftSpinner.hide()
}
}
Instead of adding code of ActivityIndicator in prepare(for:sender:) method you need to call it in the Button action and after that call performSegue(withIdentifier:sender:) method.
#IBAction func onBtnSkip(_ sender: UIButton) {
SwiftSpinner.show("Loading") // Act. indicator found on github
willRunOnce() // Here Im saving data to CoreData
SwiftSpinner.hide()
//Now performSegue
self.performSegue(withIdentifier: "identifier", sender: nil)
}
Related
I am trying to make a segue to a table view controller when a button is tapped in my view controller programmatically. Here is my code:
#objc func editProfileButtonAction(sender: UIButton!) {
print("ButtonTapped")
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
var editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
}
I really could use some help. I also need to make a segue to a collection view controller using a button in the same view controller.
Okay to clarify that. There is no way to create a segue programmatically. Segues are the arrows on storyboard linking from one to another VC. They are called with: performSegue. This calls the function prepare.
If you want to show a new VC when hitting a button (without segue), then you use the present(VC(), animated: true, completion: nil) } inside the button function. The VC is presented modally.
#objc func editProfileButtonAction(sender: UIButton!) {
print("editProfileButtonAction")
present(EditProfileTableViewController(), animated: true, completion: nil)
}
Make sure, that the segue in the Storyboard has exactly the identifier: "EditProfile". Normally I'm writing identifiers with lower letter in the beginning. You also need to prepare for Segue. For example set the delegate:
// Set ViewController class as the delegate of the EditProfileTableViewControllerDelegate protocol
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "EditProfile" {
let editProfileTableViewController = segue.destination as! EditProfileTableViewController
editProfileTableViewController = self
}
}
}
At one point in my coding time, I deleted all my storyboard because of too many error's that I could hardly solve. Now I'm doing it all programmatically. At first it was a bit hard to set up all the view's by myself but after all I'm very glad I'm not using storyboards anymore. For some stuff I need xib's, and for testing storyboard. Just if you're interested: the most iOS programmers are using storyboard, so it's okay if you go on with that.
The advantage of doing it all programmatically is that there are no segue's anymore. So just present, and on navigation VC's push, pop, ...
I have created a ViewController with a view and a button. I have declared the button as an outlet and as an Action in the viewcontroller. Additionally I am passing the data of the first Viewcontroller to the second Viewcontroller with a segue. When I click the cancel button which executes a segue back to the first viewcontroller I get the error
Thread 1: signal SIGABRT.
The error is shown in the prepare function which is passing the data. I have already controlled the connection inspector. I don't know what is wrong with my code.
here is my code:
#IBAction func cancelButton(_ sender: Any) {
performSegue(withIdentifier: "backToFirstScreen", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let tableViewVC = segue.destination as! tableViewController
tableViewVC.passwordNotes3 = passwordNotes2
tableViewVC.passwordCategory3 = passwordCategory2
tableViewVC.passwordStrings3 = passwordStrings2
}
I think the problem here is that you havent created a "backToFirstScreen" segue that starts in the second view controller and ends in the first viewcontroller.
Using a segue to go back to the first screen is slightly taboo; I would replace
performSegue(withIdentifier: "backToFirstScreen", sender: self)
with
self.dismiss(animated: true, completion: nil)
or if you're using a navigation controller
self.navigationController?.popViewController(animated: true)
This allows you to dismiss the current viewcontroller youre looking at and return to the view controller which presented it without having to create a segue that goes in reverse. Just make sure you have a segue that goes from the first view controller to the second view controller in that order.
I am totally new to the Mac apps development. I am facing an issue since last two days but could not succeed.
My problem is the same as question Swiching between 2 diferent NSViewControllers with data.
Could you please help me to understand the process and syntax of how to move from one NSViewController to another.
I have a View controller for login where I have two fields i.e. UserId and password.
On the click of the login button a web API is called to authenticate the user and upon receiving "SUCCESS" as the response, control should be transferred from LoginViewController to ProfileViewController.
I have tried to resole this issue as per the answer of the question (link given) but I am getting an error that. "fromviewcontroller.view.superview cannot be nil."
Create a segue from LoginViewController to ProfileViewController and give an identifier to it like "showProfile".
#IBAction func loginButton(_ sender: Any) {
// Code for validating User.
if response == "SUCCESS" {
performSegue(withIdentifier: "showProfile", sender: sender)
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "showProfile" {
let profileController = segue.destinationController as! ProfileViewController
profileController.data = responseData
}
}
Not using storyboards?
#IBAction func loginButton(_ sender: Any) {
// Code for validating User.
if response == "SUCCESS" {
let profileController = ProfileViewController(nibName: "ProfileViewController", bundle: Bundle.main)
profileController.data = responseData
self.view.window!.contentViewController = profileController
}
}
You have to create a Segue in your Storyboard (Ctrl + Left click the yellow circle button above your LoginViewController and drag it to your ProfileViewController) and then name it something like "showProfile".
When you received your "SUCCESS" you want to call:
//here you enter the name of the segue you want to call
//& in sender the data you want to pass to the new VC.
performSegue(withIdentifier: "showProfile", sender: nil)
this will call
prepare(for segue: UIStoryboardSegue, sender: Any?)
in your current ViewController, so if you want to pass data to your new ViewController, you need to override it.
Example for passing data between ViewControllers :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//asking which segue is called
if segue.identifier == "showProfile" {
//when you called "showProfile", you can be sure that your
//destination is a ProfileViewController
let vc = segue.destination as! ProfileViewController
//passing the data to your new VC
vc.data = sender
}
}
So I experimented with these 2 different ways of declaring a ViewController variable and it seemed to offer me the same results. However, I do feel there must be a difference between setting the destinationVC variable because if not, won't people use the more straightforward way of just declaring a new object?
[using segue.destination as! ViewControllerName]
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "changeCityName" {
let destinationVC = segue.destination as! ChangeCityViewController
destinationVC.delegate = self
}
}
[using ViewControllerName()]
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "changeCityName" {
let destinationVC = ChangeCityViewController()
destinationVC.delegate = self
}
}
In the prepareForSegue method, these two methods of creating a new VC differs greatly.
If you use segue.destination, you refer to the specific VC that the segue is going to, i.e. the one in your storyboard that the segue is connected to. If you create a new VC, then the VC you created won't be the same one as the segue is going to. i.e. you are dealing with a separate VC. Setting the delegate of the newly created VC won't do anything to the VC that is actually being presented.
If you are talking about the difference between using a segue to present a VC and this:
let vc = SomeViewController()
self.present(vc, animated: true)
Then the difference is less. If you use segues, then the views in the view controller will be read from the storyboard (NIB) file. If you create the VC by calling the initializer, you will have to handle adding the views in your view controller class.
Result may be visually same but its not true.
If you don't put any code inside prepare(for segue) still you will get same result(visually)
prepare(for segue) is called when UIViewControllers are connected through storyboard.
Since UIViewControllers are already connected in storyboard, so the destination UIViewController is called on your desired event.
In your first case using (segue.destination as! ViewControllerName) which is correct way of using segue.
Before going further one more thing is to be discussed about and that is
Why we are required to write code inside prepare(for segue) if its already connect through storyboard
1.From one button action you can connect several segues depending on your requirements, but each time button is pressed same prepare(for segue) method will be called, so to differentiate which UIViewController is to be called we do something like this
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "FirstViewControllerIdentifier")
{
}else if(segue.identifier == "SecondViewControllerIdentifier"){
}else if(segue.identifier == "ThirdViewControllerIdentifier"){
}else{
// and so no
}
}
Now here we get object of destination controller(UIViewController) already being prepared.So we are not required to make a new object of destination controller
2.We can pass data to destination controller and also we can set delegate
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "FirstViewControllerIdentifier")
{
// here we get object of first view controller and set delegate
let firstVC = segue.destination as! FirstViewController
firstVC.delegate = self
}else if(segue.identifier == "SecondViewControllerIdentifier"){
// here we get object of second view controller and pass some data to it
let secondVC = segue.destination as! SecondViewController
secondVC.someData = someData
}else if(segue.identifier == "ThirdViewControllerIdentifier"){
}else{
// and so no
}
}
Now in your second case using ViewControllerName() (the wrong code)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "FirstViewControllerIdentifier")
{
// here we create object of first view controller.This object is different from the destination view controller
//you create an object and set a delegate but after that you are not using that object and that object is totallu useless.
let firstVC = FirstViewController()
firstVC.delegate = self
// above code does not affect any thing but the contoller which is to be presented is destination view controller which is connected through storyboard
}
}
Hope you understand how to use segue and let me know if there is any problem
I have a view controller with a lot (36) of buttons, and I want each of these buttons to segue to a particular view controller based on a variable that was set earlier in the program. In other words, any button could potentially go to 15 different view controllers based on a variable that was sent to the viewcontroller containing the buttons...
I think I can make this work if I click and drag each button to every viewcontroller... but it seems silly and messy.
I tried doing something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
send.variablesent = (sender as! UIButton).title(for: .normal)!}
}
But this only works if I click and drag the button in the storyboard to the "AViewController".
Any help is appreciated, thanks!!
For that you can make segue from SourceViewController to DestinationViewController instead of from Button to Controller, After that when you call perfromSegue in your button action then pass button reference as sender in perfromSegue call.
#IBAction func buttonAction(_ sender: UIButton) {
self.performSegue(withIdentifier: "segueIdentifier", sender: sender)
}
Now in prepareForSegue cast sender to UIButton and set title according to it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
if let button = sender as? UIButton {
send.variablesent = button.titleLabel?.text ?? "Default value"
}
}
}