Passing an NSManagedObject Effectively through Storyboard - ios

I have quite a complicated setup in my app that involves an embedded UISplitViewController which feeds a bunch of UIViewControllers.
What I am needing to do is pass an NSManagedObject through the embedded UISplitViewController so I can access it in my separate detail' UIViewControllers.
I have attached an image of my storyboard with some awesome annotations....
This is my prepareForSegue function at the minute, this is in the View Controller where I already have my NSManagedObject, I am looking to pass it to the first SurveyViewController so it can get passed on:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println("Sender is \(sender)")
if segue.identifier == SurveyIdentifier {
// let nav : UINavigationController = segue.destinationViewController as! UINavigationController
// let itemVC: BACUploaderViewController = nav.topViewController as! BACUploaderViewController
let surveyViewController: SurveyViewController = segue.destinationViewController as! SurveyViewController
println("survey view controller: \(surveyViewController)")
// if let destination = segue.destinationViewController as? MasterViewController {
//
// destination.workItem = sender as? Work
// }
}
}
I am fairly sure that I have to access my MasterViewController from here by drilling down through the View Hierarchy, but not sure on how to achieve this effectively?
On a side note, the segue does work, I am presented with the correct views, but it pushes the view onto the screen twice and I'm not sure why, I can upload a gif of this if seeing what I am talking about in action might make more sense?

You can "reach down" through the hierarchy of view controllers, to get a reference to the table view controller titled "Sections" in the storyboard.
From prepareForSegue in your SurveyViewController:
// the destination of the "embed" segue will be the split view controller
let splitVC : UISplitViewController = segue.destinationViewController as! UISplitViewController
// in a UISplitViewController, viewControllers[0] represents the Master view controller
// in your case that is a UINavigationController...
let navVC: UINavigationController = splitVC.viewControllers[0] as! UINavigationController
// In a UINavigationController, topViewController represents the visible VC
// In your case that's the Sections table view controller...
let sectionsVC : SectionsViewController = navVC.topViewController as! SectionsViewController
// (replace "SectionsViewController" with the correct class name)
sectionsVC.object = yourNSManagedObject
This passes the object to the Sections view controller. You can pass the object to the final VCs (the bad boys!) in the prepareForSegue of the Sections view controller. You can't do it earlier, because they are not instantiated before then.
As to why the view might be pushed onto screen twice, my only guess is that you might be using performSegueWithIdentifier from within didSelectRowAtIndexPath of a table view, when the segue is also linked directly to the prototype cell.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println("Sender is \(sender)")
if segue.identifier == SurveyIdentifier {
// let nav : UINavigationController = segue.destinationViewController as! UINavigationController
// let itemVC: BACUploaderViewController = nav.topViewController as! BACUploaderViewController
let surveyViewController: SurveyViewController = segue.destinationViewController as! SurveyViewController
***********************
surveyViewController.managedObject = self.managedObjectContext
************************
// if let destination = segue.destinationViewController as? MasterViewController {
//
// destination.workItem = sender as? Work
// }
}
}
You can have an optional named managedObject in your SurveyViewController and then inject your managedObjectContext object from MasterViewController to SurveyViewController. This code snippet is written keeping in mind that you are in MasterViewController

Related

prepareForSegue not working with a Navigation Controller

I have a View Controller with an activity indicator to get data from my database. Once all the data is fetched, this view will performSegueWithIdentifier and use prepareForSegue to pass the data to a TableViewController. The issue that I am experiencing is that if I add a Navigation Controller in between the view that fetches the data and the TableViewController getting the data prepareForSegue does not work, I don't see the data on the TableViewController. However, if I remove the Navigation Controller I get the data just fine. Below is my prepareForSegue method. I am embedding a Navigation Controller there in order to get the transition effect I want with this segue which should have the TableViewController slide in from the left with a push segue. Thanks
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "serviceView" {
if let destination = segue.destinationViewController as? ServiceTableViewController {
destination.firstName = self.firstName
destination.lastName = self.lastName
destination.email = self.email
destination.streetAddress = self.streetAddress
destination.aptOrSuite = self.aptOrSuite
destination.state = self.state
destination.city = self.city
destination.zipcode = self.zipcode
destination.phone = self.phone
}
}
}
embed the view controller that fetches the data in a navigation controller not the table view controller, so both view controllers are in the navigation controller's stack of view controllers
First you need to access the NavigationController, then the topViewController, casting topViewController as your destination NavigationController
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController as! serviceView
targetController.firstName = self.firstName

how send data to new view [duplicate]

This question already has answers here:
Sending data with Segue with Swift
(5 answers)
Closed 6 years ago.
please help. I need send data from view to new view. I have that StoryBoard.
StoryBoard
In first view i have code
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "LEDChangesSegue" {
let changeLED = segue.destinationViewController as? AddLED
changeLED?.senderCell = sender as? LEDListCell
changeLED?.ledController = sender!.ledController
changeLED?.update = true
}
}
this method worked when I use push segue, but now I use modal segue and in segue.destinationViewController
is NavigationController, not my TableViewController
Each navigation controller has array of presented controllers. As well if your Controller is on top(is shown right now) you can use this code to get it navigationController.topViewController
Otherwise you need to go through all controllers and get yours using this code
let navController: UINavigationViewController = segue. destinationViewController
for let controller in navController.viewControllers {
if let neededController = controller as? YourControllerType {
// your action
}
}
As well you can create your custom segue with IBInspectable property of UIViewController that will store your controller inside. After that you can cast this your segue to your custom segue and get your controller from that property.
Use the new destination as VC to call your next tableViewController
let destination = segue.destinationViewController
if let navcon = destination as? UINavigationController {
destination = navcon.visibleViewController!
}
if let hvc = destination as? TableViewController{
// do whatever
}

prepareForSegue destination TableViewController

I currently have a button set to go to a TableViewController but decided I wanted to embed that TableViewController in a TabBarController. Well before I did this I had this bit of code in the previous ViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "showListSegue"){
let des = segue.destinationViewController as! TableViewController
des.jsonfile = self.jsonfile
}
}
Now when I try and click the button it give me this error.
Could not cast value of type 'UITabBarController' (0x111c818b0) to
'Forkit.TableViewController' (0x10d1b1490).
I tried the following code with no success as it gives me this error
Value of type "UITabBarController" has no member 'jsonfile'.
let des = segue.destinationViewController as! TableViewController
How can I get around this?
The segue showListSegue now has your TabBarController as it's destinationViewController. This is why it can not cast it to TableViewController, because it's not the one you're looking for. The TabBarController does contain a reference to the ViewController you want though. You likely have two options:
1: Use .viewControllers and find your view in there, like this:
let tabBarController = segue.destinationViewController as! UITabBarController
let des = tabBarController.viewControllers![0]
In which [0] selects which tab's ViewController you need.
2: Select the right tab and use .selectedViewController
let tabBarController = segue.destinationViewController as! UITabBarController
tabBarController.selectedIndex = 0 // choose which tab is selected
let des = tabBarController.selectedViewController!
Please be aware that you are working with optional values here, so either be absolutely sure you can safely unwrap, or build in checks (casting with as? and if let statements, etc.).
More information: UITabBarController Class Reference
Try This
#IBAction func about(sender: AnyObject) {
performSegueWithIdentifier("about", sender: sender)
}

Could not cast value of type 'TableViewController' to 'TableViewController'

I'm trying to pass Realm data from Custom cell to Detail TableView Controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTask" {
let nextViewController = segue.destinationViewController as! TaskViewTableViewController
let indexPath : NSIndexPath = self.tableView?.indexPathForSelectedRow as NSIndexPath!
let task = tasks![indexPath.row]
nextViewController.name = task.name
nextViewController.notes = task.notes
nextViewController.date = task.date
nextViewController.timeLength = task.timeLength
}
}
I'm getting error
Could not cast value of type 'Taskio.TaskListTableViewController'
(0x10001f028) to 'Taskio.TaskViewTableViewController' (0x10001f280).
Also tried
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTask" {
let nav = segue.destinationViewController as! UINavigationController
let nextViewController = segue.destinationViewController as! TaskViewTableViewController
let indexPath : NSIndexPath = self.tableView?.indexPathForSelectedRow as NSIndexPath!
let task = tasks![indexPath.row]
nextViewController.name = task.name
nextViewController.notes = task.notes
nextViewController.date = task.date
nextViewController.timeLength = task.timeLength
}
}
and also
let nextViewController : TaskViewTableViewController = segue.destinationViewController as! TaskViewTableViewController
EDIT
Forgot to put class name into storyboard of tableViewController. It's working
For me the problem was i forgot to put class name in storyboard
It seems that your destinationViewController is not of the type that you are expecting. You will need to check the segue to make sure it's pointing to the correct controller. If it is, you'll need to revisit your controller class hierarchy.
Are TaskListTableViewController and TaskViewTableViewController part of the same class hierarchy? Per the Swift docs on typecasting, you can only downcast from TaskListTableViewController to TaskViewTableViewController if your List view is a subclass of your Task view. It is not enough that both are simply subclasses of UITableViewController.
In other words, if your class hierarchy looks like this, you will not be able to downcast from the List view to the Task view:
----> TaskListTableViewController
/
UITableViewController
\
----> TaskViewTableViewController
But if your hierarchy looks like this, you will be able to downcast from one to the other:
UITableViewController -> TaskListTableViewController -> TaskViewTableViewController
Regarding your second attempt at casting to UINavigationController, the navigation controller is not related to UITableViewController at all, so it cannot be type casted to that class either.
You can check out the inheritance hierarchy for UINavigationController and UITableViewController. One needs to be a subclass of the other for any type casting to work. You'll see that is not the case.
If I understand from the error message, you are attempting to cast a TaskListTableViewController to TaskViewTableViewController.
The destination is a TaskListTableViewController so you have to treat it like one.
let nextViewController = segue.destinationViewController as! TaskListTableViewController

Swift - Could not cast value of type 'UITabBarController'

I have a login screen that takes credentials, and based on outcome of verification, user is redirected to another view controller or not. The login view controller is controlled by NavigationController and once the login is successful, user is redirected to a Home view controller controlled by UITabBarController.
When I trigger the segue, it says the following error:
Could not cast value of type 'UITabBarController' (0x10d414030) to
'Mawq.HomeViewController' (0x10a7ed220).
Here is the code for the segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showHomeFromLoginSegue") {
/*Provide ServiceToken a value from API*/
// pass data to next view
let destinationVC = segue.destinationViewController as! HomeViewController
destinationVC.userObject = self.userObject;
}
}
Any idea how to overcome this issue?
Since your segue is connected to a UITabBarController, you need to cast it to UITabBarController and get the ViewController object using the viewControllers property of the tab bar controller.
let tabCtrl = segue.destinationViewController as! UITabBarController
let destinationVC = tabCtrl.viewControllers![0] as! HomeViewController // Assuming home view controller is in the first tab, else update the array index
destinationVC.userObject = self.userObject;
For Swift 4:
let tabCtrl: UITabBarController = segue.destination as! UITabBarController
let destinationVC = tabCtrl.viewControllers![0] as! HomeViewController
destinationVC.userObject = userObject[String!] // In case you are using an array or something else in the object

Resources