Make a segue to a tableview controller from a view controller - swift

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, ...

Related

how can i fix the error "Thread 1: signal SIGABRT"?

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.

connect segue to Navigation control

Before I used a Segue to transfer data between to view controllers.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Edit List" {
if let currentTodo = todoReadyForEditing, let editControler = segue.destination as? ListPageController {
editList.prepare(for: currentList)
}
Now the plan is changed I should transfer the data from the first view controllers to a tableViewController. Since I want to have a navigation bar to the tableViewController page, I added a navigationBarController before it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Edit List" {
if let currentTodo = todoReadyForEditing, let editControler = segue.destination as? ListTableViewController {
editList.prepare(for: currentList)
}
The problem is when I connected segue directly to UITableViewController, everything is work, same as before that I have two view controllers, but the navigation bar is hidden, which I don't want. As I read, apparently i have to connect the segue first to the navigationViewController, but when I did not, the data won't transfer to the table view controller.
Is there any suggestion? Thanks for your help in advance
Destination of segue is UINavigationController, but you can work with its topViewController property which is your controller
guard let navCon = segue.destination as? UINavigationController,
let controller = navCon.topViewController as? ListTableViewController else { fatalError("Segue wasn’t set right") }
Anyway, I would suggest you don’t use segues and create your UINavigationController with embedded controller programmatically

Difference Between 2 Ways of Declaring a ViewController Object

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

Swift: UICollectionView + Custom Segue makes problems

In the following application, I am using an UICollectionView. The text of each cell (string) is downloaded from my SQL-Server. This works pretty well. But somehow, my app sometimes looks as it should, but sometimes not (this happens in simulator, as well as on a native device).
I guess it has something to do with the custom segue I am using, when clicking the settings button (down-right).
#IBAction func settingsButton(_ sender: UIButton) {
// in order to prevent an exception, you have to add an Identity in Main.storyboard
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
// instantiate view controller by storyboard
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
// custom segue
self.performSegue(withIdentifier: "SegueToRight", sender: sender)
// pass email
nextViewController.email = self.email
// switch view controller
self.present(nextViewController, animated:true, completion:nil)
}
Displayed right:
Displayed wrong:
Your problem is probably caused because you are using two different presentation methods, a segue and a present.
Try to remove self.present(nextViewController, animated:true, completion:nil) since the performSegue function will handle the transition for you already.
Also, nextViewController.email = self.email should be set before performSegue to ensure that the data will be passed to the next controller properly.
UPDATE FOR COMMENTS
You need to split your code in two. Inside the #IBAction invoke the performSegue call:
#IBAction func settingsButton(_ sender: UIButton) {
// custom segue
self.performSegue(withIdentifier: "SegueToRight", sender: sender)
}
Then override prepareForSegue:sender::
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextViewController = segue.destination as! SettingsViewController
nextViewController.email = self.email
}

nothing happens on trying to dismiss popover viewcontroller Swift

I have a viewcontroller that is presented as popover when the user clicks on an ImageView.
The problem is, I added a button to dismiss it but when I tap on it nothing happens.
The code I have is:
#IBAction func onCloseTapped(_ sender: Any) {
presentedViewController?.dismiss(animated: true, completion: nil)
}
I've also tried dismiss(animated: true, completion: nil) and other methods, but still nothing.
Can anyone tell me what I am doing wrong?
Edit: Posting a screenshot:
Edit 2: I'm presenting it from the storyboard. I've added a gesture recognizer on the image, then added segue from the storyboard that says present as popover, then anchor to the image.
it won't work because when you show as popover, the viewController doesn't have the navigationController. You have to create a delegate method and use the dismiss function on the viewController that make the call to the popover.
Here an exemple:
make the popover delegate, in the popover viewController:
protocol PopoverViewControllerDelegate: NSObjectProtocol {
func dismiss()
}
then you create a delegate variable and call when the button is tapped:
var delegate: PopoverViewControllerDelegate?
#IBAction func onCloseTapped(_ sender: Any) {
delegate?.dismiss()
}
Now in the viewController that call the popover you override the prepare for segue method to set the popover delegate:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popover" {
if let vc = segue.destination as? PopoverViewController {
vc.delegate = self
}
}
}
Now you just need to use the delegate to dismiss your popover viewController:
extension ViewController: PopoverViewControllerDelegate {
func dismiss() {
navigationController?.dismiss(animated: true, completion: nil)
}
}
Don't forget to put the identifier for you segue, the identifier that we use is this = "popover"
Hope that help you.