Pass data from ViewController (not Detail) to MasterViewController in UISplitView Swift - swift

How to pass data from ViewController (VC) to MasterView (MV) in UISplitView? As I figured out I can't use segue because it goes from VC to SplitView, not to MV.
Check please picture below
screenshot of storyboard
UPD:
Thanks Stepan for the help, I have figured out.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toMessurementVM"{
let splitVC = segue.destinationViewController as! UISplitViewController
let navVC = splitVC.childViewControllers.first as! UINavigationController
let vc = navVC.childViewControllers.first as! MessurementTagsTableView
vc.ingredient = passingIngredient
}
}
I am not sure that this is right way, but it works.
There are many examples of how to pass data from Detail to Master and vice-versa, but there is nothing for my case.
Thanks

1) don't pass data! just use pointers.
2) you can get SplitViewController with superview from MasterView or ViewController
3) register for notification in controller you need and then just send notification that some data ready.
4) on destination controller which catch your notification - just get data with pointer with get superview from controller, cast it to SplitViewController and then you can get master or detail from it with no problems, and then get data from it by pointer.
5) use debugger stop and see what you have in superview, and then You will know exact how to act )
6) make sure to call all UI operation on main thread.

Related

Navigation controller between two UITableViewControllers in Swift

I am looking for a way to insert a navigation controller between two UITableViewControllers. I have a UITabBarController which then connects to a UITable which then connects to another UITable. I have attached a picture below to give a better reference at what I am talking about.
So from UITabBar, you go to the first table, from that, you make a selection and go to another table. The second table is where I want my back button. I know in the screenshot you can see the back button present but for some reason it does not show it at run time.
Moreover, when I try to embed Navigation Controller in the first table, I get an error in the code below.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let barViewControllers = segue.destination as! UITabBarController
let destinationViewController = barViewControllers.viewControllers?[0] as! MainVC
destinationViewController.TPNumber = txtTpNumber.text!
destinationViewController.intake = intake
let DVC = barViewControllers.viewControllers?[1] as! AttendanceTVC //This is where I get an error
DVC.TPNumber = txtTpNumber.text!
}
If anyone could guide me on how I can solve this? Thanks!
Go to your storyboard and click your Attendance (ViewController), than click your menu "Editor" -> "Embed in" -> UINavigationController.
You can firstly cast this destination as UINavigationController and then you can access the controller embed in UINavigationController by it's topViewController property

How to properly access a child view controller

I have a UIViewController inside a container view on my main view controller. I'm trying to un-hide the child view controller and perform a function on the child view but I don't know how to properly access it.
I've tried this:
let ChildVC = children.first as! ChildView
ChildVC.RunFunction()
But this does not work as I have multiple child views.
let ChildVC = storyboard?.instantiateViewController(withIdentifier: "Child") as! ChildView
ChildVC.RunFunction()
I've then tried this, but when the RunFunction() function is executed, it throws a lot of errors saying the things inside it are nil. (The error is not with the run function as it works fine when accessing via the children.first method)
How do I specify the exact childViewController without using the children[1] (or what ever number the childViewController is) method?
Any help would be much appreciated!
Since you mention a "container view" I am assuming you invoke the child view controller using an embed segue.
Assuming that's the case you should implement a prepare(for:sender) method that saves a pointer to the child:
Give the parent view controller an instance variable:
var childView: ChildView?
And then in your prepare(for:sender) method
func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if let dest = segue.destination as? ChildView {
childView = dest
}
}
Then when you need to send messages to the childView:
childView?.runFunction()
(Method names should start with lower-case letters)

How to pass data between two screens while both are elements in NavigationController in Swift?

I have a set of storyboards under the UINavigation Controller. One of these screens contains a table view and I need to send the data of the clicked row to the next screen. I am aware that doing so would require me to use segue. But then how do I get the Navigation Bar and the Navigation Button
For better understanding I have uploaded the screen shot of my first screen. Clicking on the detail button is going to send the challenge object to next screen. However, I am looking forward to having the same navigation bar on the top of the next scree. Any idea how can I accomplish such objective?
Currently if I press on details button, I'll get the details of that challenge in the terminal.
#IBAction func CAStartChallenge(_ sender: UIButton) {
let tag = NSNumber(value: sender.tag) as! Int
print("challenge name to be printed : \(challengeTableConent[tag].display()) ")
}
In your storyboard you want to drag a segue between the view controllers, like so:
Storyboard segue dragging
Use either Show or Push (deprecated) options for the segue. Give this segue an appropriate identifier, such as Details.
Then in your button function you can add these:
#IBAction func CAStartChallenge(_ sender: UIButton) {
let tag = NSNumber(value: sender.tag) as! Int
performSegue(withIdentifier: "Details", sender: challengeTableConent[tag])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Details",
let destination = segue.destination as? DestinationViewController,
let model = sender as? ChallengeTableContentType {
// pass through model to destination view controller
destination.model = model
}
}
You can then configure the destination view controller using its specific model when it appears.
First of all
Passing data through screens using segues is simple. Just check this answer
Pass data through segue
It will explain exactly how to do it
Second
Check the bug on your button I think you mean "Details"
Third
Check the type of segue, you might not used push or show detail. Also select the details view and make sure that "Simulated Metrics -> Topbar" is set to inferred
Some prints to help
This will ensure that the navigation bar comes from the previous controller
This is how your segue should look, do not forget to give an identifier to your segue

Cannot pull data between view controllers: Swift 3

I have a view controller with a name input text box in it. I want to be able to pull the name.text value from my main view controller, but I'm struggling with the code.
Sorry, I know there are similar questions, I am struggling to understand where I am going wrong though, here is my code:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "statsegue" {
let statVC = segue.destination as! SecondViewController
NameLabelMain.text = statVC.NameDisplayStat.text
//or try that if above doesn't work: detailsVC.passedString = recipes[indexPath?row]
}
}
This is on my main page, trying to pull the data from my second view.
Any thoughts or suggestions would be awesome.
Thanks
This is a common timing problem.
In prepareForSegue the view of the destination view controller is not loaded yet so all IBOutlets are not connected yet (aka not available).
You can only access data which is available right after initialization.
However generally you are passing data from the source controller to the destination controller rather than the other way round.

How To Dismiss Popover From Destination View Controller in Swift

I have a main view controller that has been setup in Interface Builder to open a table view controller via popover segue connected to a button. I want to be able to dismiss the popover when an item inside of my popover table view is selected in didSelectRowAtIndexPath. In Objective-c I can just typecast the the segue in the prepareForSegue delegate to a UIStoryboardPopoverSegueand pass along its UIPopoverController to the table view controller. However, in Swift my downcast fails because it sees the segue as type UIStorybaordPopoverPresentationSegue (when stepping through with the debugger) which doesn't appear to be a public API.
Here's my code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "ShowCollectionsSegue" {
if let collController:CollectionsTableViewController! = segue.destinationViewController as? CollectionsTableViewController {
if let popoverSegue = segue as? UIStoryboardPopoverSegue { // <-- This fails
collController.popover = popoverSegue.popoverController
}
}
}
}
How do I coerce the segue to a UIStoryboardPopoverSegue in order to access its popoverController property?
I'm open to solving the problem of dismissing the popover in response to a table view cell tap a different way, but it seems that when using a segue from the storyboard, the only way to dismiss the popover is by holding onto a reference to the popover controller somehow and the only way to do that as far as I can tell is to cast the segue to a popover segue which Swift doesn't want to let me do. Any ideas?
A strange problem, indeed. I noticed in the documentation, that UIStoryboardPopoverSegue does not inherit from any class. That explains why the cast does not work - UIStoryboardSegue is not its superclass. So I just tried to create a new object - it looks weird but works:
let popoverSegue = UIStoryboardPopoverSegue(
identifier: segue.identifier,
source: self,
destination: segue.destinationViewController as UIViewController)
println("Is there a controller? \(popoverSegue.popoverController.description)")
// YES !!
EDIT
But this controller will not dismiss the popover :(
The fix is to specify the segue in Interface Builder as "Deprecated Segues : Popover". Then the code would be as expected
let popoverSegue = segue as UIStoryboardPopoverSegue
if let destination = segue.destinationViewController as? TableViewController {
destination.delegate = self
self.popoverController = popoverSegue.popoverController
}