Swift 3 Dismiss after performing segue - swift

I have three controllers connected with segues.
Controller one is MyNotif, controller 2 is AddNotif and controller three is SelectInterval.
From controller 2 I have a segue to controller 3 and then back to controller 2.
This is because in controller 3 i will select from a tableview a value (string) which will be inserted in a field in controller 2.
When the segue from 3 to 2 is performed the controller is not dismissed. This means that if from controller 2 I press the back button (I do not use a navigation controller, the back button is a simple button. Here's the code:)
#IBAction func backBtnPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
I will land on controller 3 instead that on controller one.
To summarise I'm trying to achieve this:
From controller 1 I go to controller 2. From here I can go to controller 3, select the string I need, perform the segue, go back to controller 2 (and till here everything works fine). Once back on controller 2 i f I click the back button i would like to go back on controller 1 (now what happens is that i go back on controller 3).
A bit complicate explain... hopefully it is a bit clear.
here's my segue code:
AddNotif:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SelectRepeatInterval" {
if let destination = segue.destination as? SelectRepeatIntervalVC {
destination.selectedRepeatingInterval = repeatingInterval
}
}
}
SelectInterval:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as! SelectRepetaIntervalCell
selectedInterval = currentCell.repeatIntervalLbl.text!
performSegue(withIdentifier: "IntervalSelected", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "IntervalSelected" {
if let destination = segue.destination as? AddNotificationVC {
destination.repeatingInterval = selectedInterval
}
}
}

What you are looking for is presentingViewController https://developer.apple.com/documentation/uikit/uiviewcontroller/1621430-presentingviewcontroller
if let destination = self.presentingViewController as? AddNotificationVC {
destination.repeatingInterval = selectedInterval
}
dismiss(animated: true, completion: nil)
Here is the complete code
tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
// Get Cell Label
let currentCell = tableView.cellForRow(at: indexPath)! as! SelectRepetaIntervalCell
selectedInterval = currentCell.repeatIntervalLbl.text!
if let destination = self.presentingViewController as? AddNotificationVC {
destination.<your textfield name>.text = selectedInterval
}
dismiss(animated: true, completion: nil)
}

Related

How can I categorize my TODOs?

I have two ViewControllers in the first I created a tableView where I can insert just a text into a cell.
In the SecondViewController I also have a tableView with the same function, bu HOW can I make it that when I click a cell in the first tableView, I can get into a separate SecondTableView (Array).
So I'm this far, but I think the categorize function must be in the didSelectRowAt, when I click a Row.
FirstViewController:
todos: This is a String Array (I want this as the Category)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "hhh"{
//let destination = segue.destination as? UINavigationController
let vc = segue.destination as? SecondViewController
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
//label name
vc?.name = todos[indexPath.row]
self.present(vc!, animated: true, completion: nil)
tableView.deselectRow(at: indexPath, animated: true)
self.performSegue(withIdentifier: "hhh", sender: indexPath)
let indexpath = todos[indexPath.row]
print("indexpath:\(indexpath)")
print("row: \(indexPath.row)")
}
}
In the SecondViewController I have a SecondArray=[String]() these are actually the Todos.
On both ViewControllers I can insert a cell with text but don't know how to pass the data back:=?
In the comments I suggested using a UISplitViewController, as this works well with any kind of master/detail type of app. (In fact, it's an Xcode project type.)
But in case you require using a UINavigationController, here's what I to to "toggle" between two views this way:
FirstViewController:
#IBAction func showFrameVC() {
updateMaskImage()
self.performSegue(withIdentifier: "ShowSecondView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowSecondView" {
if let vc = segue.destination as? FrameViewController {
vc.someValue = someValue
vc.firstVC = self
}
}
}
Basically, pass the instance of the first view controller along with any data you need to pass.
SecondViewController:
var someValue:String!
weak var subjectVC:FirstViewController!
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingFromParentViewController {
firstVC.someValue = someValue
}
}
Here you let the navigation controller do it's thing, which is pop the second view controller off the stack after passing back the data it changed. Since you are maintaining a weak value of the first view controller, you free up that memory when the second controller is released.
In your code, you are presenting your SecondViewController in 2 ways in same function.
self.present(vc!, animated: true, completion: nil)
and
self.performSegue(withIdentifier: "hhh", sender: indexPath)
intention of both lines are same, But 2 way of implementation.
if my thinking is right you don't have to perform segue (second line of code mentioned above and also No prepare for segue method).

Passing data without view transition in Swift

I have two UITableView connected through segue. I am performing segue to pass data from my firstTableView to secondTableView using tableViewCell swipe action method and saving the passed data using NSUserDefaults code works ok. But, Every time when I passed data it calls segue(I know it supposed to) and pushing to my secondTableView..I want to pass data without pushing my firstTableView to secondTableView when passing data and I have action button to access my secondController directly from mainViewController.
func tableView(_ tableView: UITableView, editActionsForRowAtIndexPath indexPath: IndexPath) -> [UITableViewRowAction]? {
let shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "xxxxxxxxxx") { (UITableViewRowAction, NSIndexPath) -> Void in
self.performSegue(withIdentifier: "shareSegue", sender: indexPath)
// self.dismiss(animated: true, completion: nil)
}
return shareAction
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "shareSegue") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destination as! ViewController
// your new view controller should have property that will store passed value
viewController.labelcell = (sendSelectedData as String as String)
}
//// I also tried the following method with no segue but the results pretty much same....
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewControllerWithIdentifier("secondTableView")
self.presentViewController(secondVC, animated: true, completion: nil)
Thanks in advance!!!

Swift prepare for segue - Send data from one view controller to another

I want to move from one view controller to another and send userId:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("chosenPerson", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId
}
by clicking I get: "fatal error: unexpectedly found nil while unwrapping an Optional value"
what I do wrong?
If you have given segue in StoryBoard DON'T Call this self.performSegueWithIdentifier("chosenPerson", sender: self) method in didSelectItem
If you have given segue in storyboard override func prepareForSegue - this method calls first after that didSelectItem calls
Please refer storyBoard once (below Image for Sample)
I think problem is in self.usersArray[indexPath.row].userId May this returns nil
Swift2:
self.performSegueWithIdentifier("chosenPerson", sender: self)
Swift3:
self.performSegue(withIdentifier: "chosenPerson", sender: self)
Swift2:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
Swift3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destination as! chosenPersonViewController
if let indexPath = collectionView.indexPathForSelectedItem {
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
}
}
When performing the segue, pass the indexPath as the sender and try using this switch statement. If you see "unknown segue" printed out when you select a cell, the destination controller is not of type chosenPersonViewController.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("chosenPerson", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch (segue.destinationViewController, sender) {
case (let controller as chosenPersonViewController, let indexPath as NSIndexPath):
controller.userID = usersArray[indexPath.row].userId
default:
print("unknown segue")
break
}
}
One possible issue could be that in your storyboard you have not set the identifier for your segue to be "chosenPerson". To fix this first make sure you have a segue between your first and second view controllers, which can be created by control dragging one from one view controller to another.
Then make sure the segue has an identifier, specifically: "chosenPerson". To do this: click on the segue between the first two view controllers, then navigate to the attributes tab, and then set the identifier box to be "chosenPerson". Save the storyboard with your changes and now you should be able to call prepareForSegue with that identifier and not experience a fatal error.

Segue is being executed twice

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
self.performSegueWithIdentifier ("Cities", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
Segue is being executed twice leading to the next VC. How can I prevent this from happening?
Delete the current segue in storyboard. Then CTRL-drag from the viewController (not the cell) to the next view controller and name it "Cities". Now, when you select a cell, the didSelectRowAtIndexPath() will fire first and will call performSegueWithIdentifier()
However, if all you're looking to do in the didSelectRowAtIndexPath() is get the row that performed the segue, you can maintain your original setup of having the cell segue from the storyboard, remove didSelectRowAtIndexPath() and in prepareForSegue() do:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = self.tableView.indexPathForSelectedRow {
self.selectedClubState = stateNamesForDisplay[indexPath.row]
}
var clubsToPassToCitiesViewController = [clubObject]()
if segue.identifier == "Cities" {
for club in clubsForTable{
if club.clubState == self.selectedClubState{
clubsToPassToCitiesViewController.append(club)
}
}
let citiesView = segue.destinationViewController as? citiesViewController
citiesView?.clubsForChosenCity = clubsToPassToCitiesViewController
}
}
You are the one executing the segue twice — once automatically in the storyboard (because your segue emanates as an Action Segue from the cell prototype), and once in code when you say self.performSegueWithIdentifier. If you don't want the segue executed twice, remove one of those.
Personally, my recommendation is that you delete didSelectRow entirely and move your self.selectedClubState assignment into prepareForSegue.

Why is my data not passing to my second view controller from a table view?

I'm trying to pass the value to a second view controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "headToDetail" {
let indexPath = self.tableView.indexPathForSelectedRow!.row
print("SELECTED INDEX \(indexPath)")
let destVC = segue.destinationViewController as! SecondViewController
print("Segue TEst \(self.toPass)")
destVC.vieSegue = self.toPass
}
I've remove the didSelectRowAtIndexPath and just going to use the Segue but when I tap on a row cell I get:
fatal error: unexpectedly found nil while unwrapping an Optional value
This is a major update to the original code.
the problem is, that you are creating a new ViewController at line
var destination = SecondViewController()
but then the controller simply deallocates because nothing is pointing to it (there is no reference to it and it falls out of scope). You haven't pushed into it, nor you performed any segue.
How to fix it? Basically there are two options.
Storyboard
If you're working with storyboards, you have to create a segue between the first ViewController and SecondViewController. You have to give it an identifier.
Then in didSelectRowAtIndexPath you will write
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
print(fruits[row])
self.toPass = fruits[row]
performSegueWithIdentifier("YOUR_SEGUE_IDENTIFIER", sender: nil)
}
then in prepareForSegue you'll set the property to the destination SecondViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YOUR_SEGUE_IDENTIFIER" {
let destVC = segue.destinationViewController as! SecondViewController
destVC.vieSegue = self.toPass!
}
}
Manual Push
The second option is to push the controller manually within the didSelectRowAtIndexPath method
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
print(fruits[row])
let destination = SecondViewController()
destination.vieSegue = fruits[row]
// if you are using navigation controller
navigationController?.pushViewController(destination, animated: true)
// if you want to present it modally
// presentViewController(destination, animated: true, completion: nil)
}
The second version doesn't force you to create segues.
It's empty because you create a new object...
var destination = SecondViewController()
...pass it your data...
destination.vieSegue = self.toPass!
...and then let it go out of scope without showing it, saving it, or doing anything else useful.