How to properly access a child view controller - swift

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)

Related

How To Pass Dictionary To Another Dictionary In A Different View Controller

I have two view controllers (autoClaimViewController and reviewAutoViewController). In autoClaimViewController, I have a dictionary (reviewTableViewData) that is made up of a struct called claimData (it contains two string variables and a UIImage variable). When the user hits the "Review" button, I want the reviewTableViewData dictionary to be passed to the second view controller so that it's data can be displayed on a table view in the second view controller (reviewAutoViewController). How do I pass this dictionary to the other view controller?
Please make your answers understandable for a beginner - I'm still learning. I'm moving between view controllers using storyboard segues.
Thanks.
Additional Question: Will the images that I stored in the variables be passed when the dictionary is passed? In other words, do images work like Integers and Strings, where they can be passed between variables without an issue?
My code:
struct claimData {
var images = UIImage()
var imageTitle = String()
var relatedUnrelated = String()
}
class autoClaimViewController: UIViewController {
var reviewTableViewData = [claimData]()
#IBAction func reviewButton(_ sender: Any) {
//PASSES THE INFORMATION TO THE REVIEW VIEW CONTROLLER
//FIX THIS... IT NEEDS TO SEND THE reviewTableViewData ARRAY.
//MAKE A DICTIONARY IN THE REVIEW CONTROLLER THAT RECEIVES THE DICTIONARY FROM THIS VIEW CONTROLLER.
let vc2 = reviewAutoViewController()
//Find out how to transfer a dictionary from one view controller to another
}
I think your best bet is to set up a segue in your storyboards which takes you from 1st view to the second view. Here is a guide.
https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html
In both views have a place to store the information you want to pass. So create a var in the secon view to hold reviewTableViewData from the first view.
Then in the 1st view you call
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is reviewAutoViewController
{
let vc = segue.destination as? TertiaryViewController
vc?.reviewTableViewData = reviewTableViewData
}
}
This get the data ready to be sent.
Then you perform the segue and the data should be passed for you. Perfomr the seugue with this func triggered by the button or whatever you use to tranisiton between views.
func performSegue(withIdentifier identifier: String,
sender: Any?){
enter code here
}

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.

Pass data from ViewController (not Detail) to MasterViewController in UISplitView 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.

Delegate between Container View and ViewController in Swift

I asked that question before, and I got the solution to what he sought. Now, I need to amplify my question. Using delegates, how can I create a Delegate to the ViewController send data to the ContainerView and ContainerView send data to the ViewController?
Well, I don't know if this is entirely what you're looking for, but what I've always done in this situation is kept a record of each view controller inside the other's class.
For example if your container view has the embed segue with identifier "Embed Segue" then your classes might look like:
Superview Class
Class ViewControllerOne: UIViewController {
var data = "This is my data I may want to change"
var subView: ViewControllerTwo?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Embed Segue" {
let destinationVC = segue.destinationViewController as! ViewControllerTwo
destinationVC.superView = self
self.subView = destinationVC
}
}
}
Embedded Class
Class ViewControllerTwo: UIViewController {
var data = "This is the other view controller's copy of that data"
var superView: ViewControllerOne?
}
Then you can pass data between these View Controllers simply by referencing self.subView.data and self.superView.data respectively.
Edit: For ViewControllerTwo to pass data back to ViewControllerOne, it would then simply have to reference self.superView.data. e.g:
Class ViewControllerTwo: UIViewController {
var data = "This is the other view controller's copy of that data"
var superView: ViewControllerOne?
func passDataBack() {
self.superView.data = self.data
}
}
This would then update the data variable in the first view controller.

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
}