Prepare function doesn't call by segue - swift

In my swift app I've this functions, I'll not specify the class because it's not important.
class ViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? LocalTVC,
let indexPath = tableView.indexPathForSelectedRow {
destination.selectedLocal = favouriteLocals[indexPath.row]
}
}
func presentLocalTVC() {
let storyBoard: UIStoryboard = UIStoryboard(name: "Home", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "localTVCID") as! LocalTVC
self.present(newViewController, animated: true, completion: nil)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.presentLocalTVC()
}
But when the tableViewControlller, LocalTVC, is presented the variables "selectedLocal" is nil.
How can I solve this?

If you are using segues, you should use performSegue(withIdentifier:sender:)
You are using present(_:animated:completion:) which is independant of storyboard delegates.

Related

Passing parameter on Perform Segue returns nil [duplicate]

I'm trying to push data from one viewController to another. I've connected a viewController to another ViewController's navigationController and then set the identifier to "showItemSegue". I get an error in these two lines:
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
Image illustration:
The code:
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
nextId = itemArray?.objectAtIndex(indexPath.row).objectForKey("objectId") as? NSString
self.performSegueWithIdentifier("showItemSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showItemSegue") {
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
}
}
The destination view controller of the segue is the UINavigationController. You need to ask it for its top view controller to get to the real destination view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showItemSegue" {
let navController = segue.destination as! UINavigationController
let detailController = navController.topViewController as! ShowItemViewController
detailController.currentId = nextId!
}
}

Change destination viewController when editing is true or false

I have a viewControllerwith a tableViewwhich contains all clubs, the user added. The user can reorder the tableViewCellswith the moverowatfunction. If he selects a club, he comes to a tableViewwith all members from the club. Now I want to implement the ability, to get to another viewController where he can edit the content of the cell.
I have created this, but now it doesn't work:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableViewClub.isEditing == true{
self.navigationController?.pushViewController(EditClubViewController() as UIViewController, animated: true)}
if tableViewClub.isEditing == false{
self.navigationController?.pushViewController(MemberViewController() as UIViewController, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if !tableViewClub.isEditing {
guard let destination = segue.destination as? MemberViewController,
let selectedRow = self.tableViewClub.indexPathForSelectedRow?.row else {
return
}
destination.club = clubs[selectedRow]
}}
When tableView.isEditing, then a viewController with a black background is shown. When !tableView.isEditing, this error is shown:Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value. I think it is because I have no storyboard segues. But is it possible, to have two segues from the tableViewCell? Or how should I solve this problem?
Don't use Interface Builder's segue. Instantiate the destination view controller manually so you can control which one you are transitioning to:
Interface Builder
Select the EditClubViewController and give it a Storyboard ID. Do the same to MemberViewController.
In code
In the first view controller:
override func viewDidLoad() {
super.viewDidLoad()
// Turn this on so rows can be tapped during editing mode
tableView.allowsSelectionDuringEditing = true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let destinationVC: UIViewController
switch tableView.isEditing {
case true:
// If your storyboard isn't named "Main.storyboard" then put the actual name here
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "editClubViewController") as! EditClubViewController
// do your setup....
destinationVC = vc
case false:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "memberViewController") as! MemberViewController
// do your setup...
destinationVC = vc
}
self.navigationController?.pushViewController(destinationVC, animated: true)
}

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

Swift 3 Dismiss after performing segue

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)
}

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!!!