How to use UITableView to push to different UIViewControllers in Swift - ios

I'm having trouble with my didSelectRowAt portion of the code.
My menu (so far) has: Workout, Tips, Contact Us. They all have a special UIViewController dedicated to their view. In my didSelectRowAt func, I have a switch case:
UIViewController.swift
switch indexPath.row {
case 0:
// Call Workout View
self.performSegue(withIdentifier: "wrkOut", sender: self)
case 1:
self.performSegue(withIdentifier: "tipsN", sender: self)
workoutView.swift
class workoutview: UIViewController {
override func viewDidLoad() { super.viewDidLoad() }
Keeping in mind "wrkOut" is the title of the Workout view and not a push segue. When I try the code it just displays a black screen when clicked. I tried ctrl dragging a push segue to each view but it can only be directed to one of them.
How can I code this to go to a specific UIViewController when the row is clicked? We have to use push segues for whatever reason.

Related

How do I use performSegue to get to another UIViewController?

I tried to connect my ViewController to a CollectionViewController with a segue between the two. I control+clicked from the ViewController to the CollectionView Controller and selected the 'show detail' segue, and then made a button with this code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("ViewController loaded")
}
#IBAction func EditCharacterSetPressed(_ sender: UIButton) {
self.performSegue(withIdentifier: "CollectionViewSegue", sender: self)
}
When I press the button in the simulator, it gives me this error message:
How do I fix this? Does it have something to do with these other warnings about my CollectionView?:
I have an Identifier, so that's not the problem:
EDIT: Problem was, he had non-existent IBAction connected to his button.
It seems like your segue does not have an identifier in your storyboard. Based on your code, it should be
CollectionViewSegue
Regarding your collection view cells. If I recall correctly (did objective-c couple of years back) xcode is creating instances of new Cell and not re-using any of the existing, because you don't have prototype cells defined.
You can (and should) create a cell (either in storyboard, or purely in code), set an identifier to that cell and reuse it in your table view controllers (or in this case in your collection view).
I guess you are just starting with the development, so I would suggest to go through couple of tutorials (e.g. http://www.thomashanning.com/uitableview-tutorial-for-beginners/)

How do I change a segue based on a UISwitch?

I'm trying to make a settings tab that changes what view the user sees in a different tab based on a UISwitch. How would I make it so that when the switch is on then the user changes to that tab, it goes to ViewController1 and when the switch is off and they change tabs, it goes to ViewController2? I've attached a screenshot that might explain it a bit better. I censored the information that would give away my app's purpose so as to not attract copycats and whatnot.
As you can see, my main problem with presenting modally full screen is that the TabBarController is eliminated, leaving users with no way of turning off the setting or looking at another tab. I don't want to present it as a popover tab or push it, because I want it to feel like nothing ever happened.
The larger view will appear modally when the switch is on and viewWillAppear is called on ViewController1. Here's my code for that:
SettingsView.swift
import UIKit
class SettingsTableViewController: UITableViewController {
#IBOutlet weak var viewSwitch: UISwitch!
override func viewDidLoad() {
tableView.allowsSelection = false
super.viewDidLoad()
}
#IBAction func switchIsChanged(_ sender: Any) {
if viewSwitch.isOn == true{
TableViewController.switchState = true
}
if viewSwitch.isOn == false{
TableViewController.switchState = false
}
}
}
I've moved the code from TabBar.swift to TableView.swift because the solution I tried doesn't really regard the TabBarController. Here's TableView.swift:
import UIKit
class TableViewController: UITableViewController {
public static var switchState: Bool?
override func viewWillAppear(_ animated: Bool) {
if TableViewController.switchState == true {
performSegue(withIdentifier: "LargeViewSegue", sender: self)
}
else {
print("Showing standard view.")
}
}
}
This code works, but as I said before, it shows no TabBar, which is essential to my app. The ideal solution is to change the relationship segue from the TabBarController to the LargeView/TableView. Unfortunately, from what I've heard, You can't create custom relationship segues programatically. If someone could prove me wrong, that would be great.
Thanks in advance.

content of the viewcontroller changes according to the segue identifier

I have multiple segues from one viewController to another viewController. In the destinationViewController I have Label and Text View that changes according to the identifier. Of course, I can manage this without identifiers and just copy and paste viewControllers, and make my storyboard even bigger, write more code. But I want to learn to write good code. So, please help me to manage the issue.
I have such picture in my storyboard:
So, each button has its own identifier. I don't pass any data from ABOUT viewController, I just change the data inside History View Controller. That is why I need to solve the problem without using prepareForSegue function (because again I don't pass any data). And if I use prepareForSegue, then I will need to manage protocols, and that means more code.
You need to pass the identifier as a parameter from the calling ViewController in prepareForSegue.
See also: Can a viewcontroller access the identifier of an incoming segue?
it's a fast example how you can do it.
//specify enum
enum SegueType: Int {
case history, about, howto
}
class AboutVC: UIViewController {
//button pressing
#IBAction func didPressHistoryButton(sender: UIButton) {
let segueIdent = "show.History"
self.performSegue(withIdentifier: segueIdent, sender: SegueType.history)
}
// in your about vc
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationVC = segue.destination as? HistoryVC {
destinationVC.segueType = sender as? SegueType
}
}
}
// in your history vc
class HistoryVC: UIViewController {
var segueType: SegueType? = nil
override func viewDidLoad() {
super.viewDidLoad()
switch segueType! {
case SegueType.history:
// segue from history button
break
case SegueType.about:
// segue from about button
break
case SegueType.howto:
// segue from how to button\
break
default:
// segue from ???
break
}
}
}

Swift: Trying to return selection to previous view controller

This seems to be a common problem, but none of the many solutions I've tried have seemed to work (or I'm not executing them properly).
I've got an image on FirstImageVC, I push a button to bring up a new view collection view controller with some custom images, the user selects one, and I want to send that image back to the FirstImageVC to overlay the original image, sort of like a sticker.
I just can't get it to execute a segue of any kind on selecting an image. Here's what I'm sort of working with in the second view controller. And it seems I may need to be adding something to the original VC, too, no?
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
prepareForSegue("backToFirstSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "backToFirstSegue"{
let vc = (segue.destinationViewController as! FirstImageVC)
vc.Delegate = self //Include this line
vc.chosenGhostPhoto = bgGhostImage?.image
}
}
EDIT 1: Here's what I did to get the unwind to work, though it's not carrying back the image selected from the collection view, which needs to be called chosenGhostPhoto.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("unwindToFirstSegue", sender: self)
}
This is how you can do this:
Step 1: Add a delegate variable on your second view controller. Please name it delegate and not Delegate - owing to naming convention.
Step 2: Define a protocol and add functions that you want your second view controller delegate to perform. Say func selectedImage(image : UIImage)
Step 3: While pushing second view from first view controller, set your first view controller as delegate of second view controller. Something like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "secondSegue"{
let vc = (segue.destinationViewController as! SecondImageVC)
vc.delegate = self
}
}
Step 4: In your second view controller once image is selected call delegate of second view controller. Below function needs to be triggered on tap on the image on second view controller.
fun imageSelected {
self.delegate.selectedImage(bgGhostImage?.image)
}
Step 5: Implement selectedImage in your first view controller and use the passed image.
An unwind segue (sometimes called exit segue) can be used to navigate back through push, modal or popover segues (as if you popped the navigation item from the navigation bar, closed the popover or dismissed the modally presented view controller). On top of that you can actually unwind through not only one but a series of push/modal/popover segues, e.g. "go back" multiple steps in your navigation hierarchy with a single unwind action.
When you perform an unwind segue, you need to specify an action, which is an action method of the view controller you want to unwind.
For your reference this is quit similar question and might help in understanding unwind segue

Different behavior for segue using UISearchController

I must be doing something wrong here.
I have a UITableView, and have implemented a UISearchController.
I have a Prototype cell linked to the details screen and pass the selected value in the prepareForSegue method.
For the normal view controller, all works OK, a row is selected and the details screen pushed (i.e. slide in from right).
However when there is an active search, using the UISearchController, the details screen is presented modally (i.e. slide up from bottom of screen) without the UINavigationBar (so there is no possibility to go "back")
I am not using didSelectRowAtIndexPath since I have used storyboard to push the details screen
Why is the presenting animation different when the same code in "prepareForSegue" is being correctly called in each case:
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier! == "PresentContactDetail") {
// pass person details from selected row
if let selectedRow = self.tableView.indexPathForSelectedRow()?.row {
let selectedPerson = self.visibleResults[selectedRow]
(segue.destinationViewController as ContactDetail).personRecord = selectedPerson
}
}
}
Any suggestions gratefully received.
in ViewDidLoad of UITableViewController set
definesPresentationContext = true

Resources