swift button press action loads tableview controller twice - ios

I have a MeterTableviewController connected to two tableview controllers with two segues. The first segue LocationListSegue is connected from a button on the MeterTableviewController directly to the LocationListTableViewController. Another segue MetersListSegue connected from the top of the MeterTableViewController to the
MeterListTableviewController.
When I press on the location button, the LocationListTableViewController gets loaded twice.
I thought it is because I was calling it twice: once from the button IBAction and another time on Prepare, so I commented the code from Prepare, but it still loads it twice.
However the MeterListTableViewController gets loaded only once.
I dont know why the button press loads the controller twice. Can someone tell me?
#IBAction func chooseLocation(_ sender: Any) {
self.performSegue(withIdentifier: "LocationListSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
/*
if segue.identifier == "LocationListSegue"{
let viewController:LocationListTableViewController = segue.destination as! LocationListTableViewController
}
*/
if segue.identifier == "MetersListSegue"{
let viewController2:MeterListTableViewController = segue.destination as! MeterListTableViewController
}
}

You have added a segue as well as segue action from button, remove one of them

Remove story board segue and change your code with my code. This is enough for you.
#IBAction func chooseLocation(_ sender: Any) {
let tableViewController = self.storyboard?.instantiateViewController(withIdentifier: "your identifier") as! MeterListTableViewController
self.navigationController?.pushViewController(tableViewController, animated: true)
}
If you want to use segue remove IBAction for UIButton and write this code.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "LocationListSegue"{
let viewController:LocationListTableViewController = segue.destination as! LocationListTableViewController
} else if segue.identifier == "MetersListSegue"{
let viewController2:MeterListTableViewController = segue.destination as! MeterListTableViewController
}
}

Related

different viewcontroller segue

I want to my app can "auto" segue from ViewControll A to b, and b to c,(a,b,c is independent viewcontroller), so I did :
defined a timer at A_ViewController, can segue from A to B to C each one minute.
set segue at on storyBoard for ViewController A and B:
A_ViewController : 'goToB' and 'goToC'
B_ViewController : 'goToC'
and overwrite "overwrite func prepare(for segue:....." in A_ViewController.
Code:
class A_ViewController: ViewController {
...//in Timer
//first 1 minute
performSegueWithIdentifier("goToB", sender: self)
//second minute
B_Controller(). goToC()
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToB" {
let B_Controller = segue.destination as! B_ViewController
B_ViewController.msg = "From AtoB"
}
if segue.identifier == "goToSearchLocation" {
let C_ViewController = segue.destination as! C_ViewController
C_ViewController.msg = searchWord
}
}
class B_Controller: ViewController {
...
func goToC() {
performSegueWithIdentifier("goToC", sender: self)
}
}
After run APP, first segue can done(Show ViewController B successfully), but after that, it always shows the error message as below :
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'goToC''
But I really set a segue 'goToC' on storyBoard. I do not know how to fix it. The code is already I modified from google search.
When you say B_Controller().goToC() you are creating a new instance of B_Controller, you aren't referring to the existing instance that was created by the goToB segue. Further, since your new instance of B_Controller isn't being created from the storyboard, it doesn't know anything about segues.
You need to store a reference to the instance of B_Controller that you are presenting in a property. Then you can use that property to invoke the goToC function.
class A_ViewController: ViewController {
var bController: B_Controller?
...//in Timer
//first 1 minute
performSegueWithIdentifier("goToB", sender: self)
//second minute
self.bController?.goToC()
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToB" {
self.bController = segue.destination as! B_ViewController
self.bController.msg = "From AtoB"
}
if segue.identifier == "goToSearchLocation" {
let C_ViewController = segue.destination as! C_ViewController
C_ViewController.msg = searchWord
}
}
class B_Controller: ViewController {
...
func goToC() {
performSegueWithIdentifier("goToC", sender: self)
}
}
You might want to re-design your code though; It would probably be cleaner to have a new timer in B that presents C rather than trying to use a single timer in A.

Downcasting Any? to UIBarButtonItem

override func prepare(for segue: UIStoryboardSegue, sender:
Any?) {
if segue.identifier == "detailSegue" {
let indexPath = tableView.indexPathForSelectedRow!
let card = cards[indexPath.row]
let detailTableViewController = segue.destination as! DetailTableViewController
detailTableViewController.card = card
detailTableViewController.picture = card.image
} else if segue.identifier == "addEditSegue" {
let addEditTableViewController = segue.destination as! AddEditTableViewController
let buttonPressed = sender as? UIBarButtonItem
if buttonPressed == cardsAddButton {
addEditTableViewController.isNewCard = true
} else {
addEditTableViewController.isNewCard = false
}
}
}
Hi, I am new to Swift. I need to perform the same segue by either tapping a UIBarButtonItem (cardsAddButton) or by tapping on cells of a UITableView. Using print statements I found that buttonPressed is nil when I tap cardsAddButton. Why? How should I check what was the sender?
You – the developer – should know who the sender of prepare(for is. There are only three possibilities:
If the segue is connected to the table view cell in Interface Builder then the sender is the UITableViewCell.
If the segue is connected to the view controller in Interface Builder then the sender is the UIViewController.
If performSegue is called in code then the sender is whatever you passed in the sender parameter (including nil).
Your code can work only if you call performSegue in the IBAction of the button and pass the button instance as sender
#IBAction func addCard(_ sender : UIBarButtonItem)
{
self.performSegue(withIdentifier:"addEditSegue", sender: sender)
}

How to navigate from one controller to another View Controller programmatically in Swift?

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "GMNewPostControllerSegueIdentifier"
{
let svc = segue.destination as? UINavigationController
let vc: GMNewPostController = svc?.topViewController as! GMNewPostController
}
}
#IBAction func newPostButtonAction(_ sender: UIButton) {
performSegue(withIdentifier: "GMNewPostController", sender: self)
}
I don't like to drag and drop from my storyboard because I have a table view in vc2.
You have many options to do this:
Using Push:
let viewController = storyboard?.instantiateViewController(withIdentifier: "viewStoryID")
self.navigationController?.pushViewController(viewController, animated: true)
You have to set ViewController ID in storyBoard like this:
Check below image , storyboard should like this
And take a reference Action for button and write like this
For button Action
Refer to the Image here
look at the picture, I want to navigate from green btn to the viewcontroller ..?

Button state info

The question is similar to "how to pass data from different viewController" but in this case I need another information, I know how to pass the data from one viewController to another but I don't know how to tell to the second viewController a specific state of an object that is in the first view. In my case I have some buttons in the first view that go in.
button.isHidden = true
after the tap, I want to tell to the second viewController which buttons have been tap, maybe I've to create a variable that represents the status of the button, but I don't know how to do, someone can help me?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" {
guard let vc = segue.destination as? FinalClass else { return }
let guest = segue.destination as! FinalClass
if let user = sender as? User {
}
}
}
where User can be something like
struct User {
var button1 = Button1 tapped
var button2 = Button2 tapped
ecc.
}
Let suppose you have two viewControllers - FirstViewController and SecondViewController.
So First,
Let Declare two Arrays in FirstViewController and SecondViewController something like -
var tappedButtonsArray = NSMutableArray() // In 'FirstViewController'
AND
var previousViewTappedButtonsArray = NSMutableArray() // In 'SecondViewController'
And here is my code to add | remove tapped buttons to | from tappedButtonsArray in FirstViewController -
#IBAction func btnTapped(_ sender: UIButton) { // Single action for all buttons
if (tappedButtonsArray.contains(sender)){
tappedButtonsArray.remove(sender) // Remove previous tapped button on unselect
}
else{
tappedButtonsArray.add(sender) // Add tapped button on select
}
}
And Here is your perform segue method:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToLast" {
guard let secondViewController = segue.destination as? SecondViewController else { return }
secondViewController.previousViewTappedButtonsArray = tappedButtonsArray
}
}
I've done with a simple array concept without any model, so that you can understand the follow. I hope it'll help you to start with.

Changing label text of second ViewController upon clicking button in first ViewController

I'm new to Swift and to iOS Development. I currently have 2 ViewControllers, a button in the first and a label in the second one. I've connected the first button to the second ViewController and the transition works.
Now, when I try changing the label's text I get the error:
fatal error: unexpectedly found nil while unwrapping an Optional
value
.
Here you find my prepare function in the first ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" {
let vc = segue.destination as! SecondViewController
vc.secondResultLabel.text = "Testing"
}
}
Can it be that the label in the second ViewController is somehow protected ?
Thanks for the help
You need to pass the String to the SecondViewController instead of directing setting it, as the UILabel has not been created yet.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" {
let vc = segue.destination as! SecondViewController
vc.secondResultLabelText = "Testing"
}
}
And in your SecondViewController viewDidLoad method set the UILabel to be the string
var secondResultLabelText : String!
override func viewDidLoad() {
secondResultLabelText.text = secondResultLabelText
}
add a string variable in the second view controller
var labelText: String!
in second view controller also (in viewDidLoad)
self.secondResultLabel.text = self.labelText
then first view controller prepare for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" {
let vc = segue.destination as! SecondViewController
vc.labelText = "Testing"
}
}
this is because second view controller's UILabel Outlet is not being initialized yet in prepare for segue
Rikh's answer is the same, both his answer and mine are the same
Welcome aboard :)
Your problem is that your SecondViewController, and more specifically vc.secondResultLabelText is not initiated when you call prepare, so secondResultLabel is actually nil at that time.
You need to add a variable to your SecondViewController like so:
var labelText: String = ""
And then set that value instead:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" {
let vc = segue.destination as! SecondViewController
vc.labelText = "Testing"
}
}
In viewWillAppear or viewDidLoad on your SecondViewController you can then use that value for your secondResultLabelText which is now ready, connected, and won't crash
secondResultLabelText.text = labelText
Hope that helps.
First take a global variable in SecondViewController... eg I took "secondViewControllerVariable". Then get the text you want to display in your SecondViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "mySegue"
{
let vc = segue.destination as! SecondViewController
vc.secondViewControllerVariable = "Your string you get in FirstViewController"
}
}
And then in your SecondViewController, in viewDidLoad method set the UILabel to be the string
var secondViewControllerVariable : String! // You have to declare this first in your SecondViewController Globally
override func viewDidLoad()
{
vc.secondResultLabelText.text = secondViewControllerVariable
}
That's it. Happy Coding.

Resources