How to use same API in other view controller in swift? - swift

I am working on a quiz app where in one view controller I am showing the questions and when I click on any of the questions it navigates to other view controller and shows question with options. Now, I want to use the same API which I have used in first view controller in second view controller. How can I do that?
In the first view controller I have used a struct like this:
struct Questions {
var id:String = ""
var user_id:String = ""
var questionset_id:String = ""
var name:String = ""
var type:String = ""
var timetosolve:String = ""
}
In the second view controller I have used the same struct in a variable like:
var data : [Questions] = []
But the problem is that I am not able to use the variables of the struct in the second view controller. I have tried to use the variable like:
questionLbl = data.name //here cannot find any variable named as 'name'
Here, questionLbl is the label where I want to use the variable.

You need to override func prepare(for segue: UIStoryboardSegue, sender: Any?) in first view controller and pass the data variable to the second one.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourSequeIdentifier" {
if let secondVC = segue.destination as? SecondVCClassName {
secondVC.data = self.data
}
}
}
Therefore you can access your data variable from second view controller. Please note that data variable is an array and you can't access values it like this data.name.

Your struct Questions should be declared in a global scope i.e in a new file "xyz.swift" or outside of ViewController class.
Which I am assuming as you said.
In the first view controller I have used a struct like this:

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
}

Checking Segue after it initiated

I have two UIViewController: A, B
Lets say there are two segues connecting them: C, D
Once a segue has been activated and I am in view B, can I know which segue got me here? C or D?
I don't know of any built-in mechanism for this, but you could have all your destination view controllers conform to a protocol SourceSegueProtocol that has a var to contain the invoking segue.
Then in the source view controller's prepare(for:sender:) method you could set that variable for destination view controllers that conform to the SourceSegueProtocol.
There is a prepare(for: segue) function that allows you to set a property in the new ViewController.
class OriginViewController : UIViewController {
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? SegueProtocol {
destination.transitionSegue = segue.identifier
}
}
}
class DestinationViewController : UIViewController, SegueProtocol {
var transitionSegue: String = ""
override func viewDidLoad() {
print("Segue: ", transitionSegue)
}
}
protocol SegueProtocol {
var transitionSegue : String { get set }
}
Edit: As per comment suggestion, it's better to expect a destination that conforms to a protocol rather than one of a specific type.

Access the presenting view controller from the presented view controller?

I have a view controller (containing my menu) presented on top of another view controller (my application).
I would need to access the presenting view controller (below my menu) from the presented view controller (my menu), for example to access some variables or make the presenting view controller perform one of its segues.
However, I just can't figure out how to do it.
I'm aware of the "presentingViewController" and "presentedViewController" variables but I didn't manage to use them successfully.
Any Idea ?
Code (from the presented VC, which as a reference to the AppDelegate in which the window is referenced) :
if let presentingViewController = self.appDelegate.window?.rootViewController?.presentingViewController {
presentingViewController.performSegue(withIdentifier: "nameOfMySegue", sender: self)
}
Here is a use of the delegation Design pattern to talk back to the presenting view controller.
First Declare a protocol, that list out all the variables and methods a delegate is expected to respond to.
protocol SomeProtocol {
var someVariable : String {get set}
func doSomething()
}
Next : Make your presenting view controller conform to the protocol.
Set your presenting VC as the delegate
class MainVC: UIViewController, SomeProtocol {
var someVariable: String = ""
func doSomething() {
// Implementation of do
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Your code goes here.
if let destVC = segue.destination as? SubVC{
destVC.delegate = self
}
}
}
Finally, when you are ready to call a method on the presenting VC (Delegate).
class SubVC: UIViewController {
var delegate : SomeProtocol?
func whenSomeEventHappens() {
// For eg : When a menu item is selected
// Set some Variable
delegate?.someVariable = "Some Value"
// Call a method on the deleate
delegate?.doSomething()
}
}
Assuming that VCApplication is presenting VCMenu, in VCMenu you can access VCApplication with:
weak let vcApplication = self.presentingViewController as? VCApplicationType
Your example self.appDelegate.window?.rootViewController?.presentingViewController is looking for the ViewController that presented the rootViewController - it will be nil.
EDIT
Per TheAppMentor I've added weak so there are no retain cycles.

Passing an array of structs from UICollectionView to DetailView and use the indexes to go from one item to another?

I have a UICollectionView that is populated by an array of productItem structs, the struct blueprint is in it's own swift file called ProductoItem.swift
struct ProductoItem {
let id: Int
let name: String
var price: String
var picture: String
var description: String
}
This works and I can successfully populate my UICollectionView with it, what I want to do now is to pass this struct to a detailView so I create this variable in the detailView.
var productos = [ProductoItem]()
And I put the following code in my prepareForSegue Method.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detalleProducto" {
let controller = segue.destination as! ProductoDetailViewController
controller.productos = productos
}
}
What I don't know how to do know is:
First as we are sending the entire array of structs I want to pass the values stored on the CollectionView cell's index to the DetailView to populate it using just the data of the product's cell, then I also want to have two buttons to go to the next / prev product that just go to the next / prev index value of my struct. How can I do this?
First, create a new 'currentIndex: Int' attribute in your detailView.
From your first UIViewController (the one that has the UICollectionView), pass the current index and the array to your DetailView:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detalleProducto" {
let controller = segue.destination as! ProductoDetailViewController
controller.productos = productos
// do whatever you need to get your index
controller.currentIndex = self.collectionView.indexPathsForSelectedItems()[0].row
}
}
Then in your DetailView, you have your array and the current index, so you can just get the info of this specific product by doing:
let currentProduct = self.productos[currentIndex]
To get to the previous or next one, you can just increment or decrement 'currentIndex'.

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.