how to pass json data other view controller - ios

Hi all am getting a data from server i.e:
{
error = 0;
"error_msg" = "Successfully Login";
success = 1;
user = {
DriverID = 35;
DriverName = "Home nath";
"com_id" = 2;
};
}
now i need to pass data of DriverName to other view controller in label box.how to do this one??

create a variable of type string in your destination view controller.
DestinationViewController.Swift
class DestinationViewController: UIViewController {
var driverName: String?
override func viewDidLoad() {
super.viewDidLoad()
print(driverName)
}
}
CurrentViewController.swift
In your CurrentViewController override prepareForSegue:sender: method.
class CurrentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destnationVC = segue.destination as! DestinationViewController
destnationVC.driverName = "Home nath"
}
}
learn how to pass data from CurrentViewController to DestinationViewController and DestinationViewController to OrignViewController it ll help you lot.
refer Passing Data between View Controllers.

Related

Segue and delegates in UIKit

I have 2 Controllers: MainVC and SideMenuVC.
I wanted to modify MainVC using SideMenuVC, so created delegate of SideMenuVC ( as well, there's Emdebed segue "name..." to "Side Menu View Controller" on storyboard because MainViewController has subView, which contains ContainerView - this container is our SideMenuVC. And this delegate works as he should.
However, due to logic in the app, I also need to send data from MAINVC to SIDEMENUVC.
So i did the same - created another delegate of second VC... But I turned out, MainViewControllerDelegate is not responding in SideMenuViewController. And i'm absolutely clueless...
Yes, i do implement necessary protocols in both classes, in extension!
Code of both VCs below, screens of storyboard in the attachment
MainViewController + MainViewControllerDelegate
protocol MainViewControllerDelegate{
func isImageLoaded(_ isLoaded:Bool)
}
class MainViewController: UIViewController {
/* ... */
var delegate: MainViewControllerDelegate?
var sideMenuViewController: SideMenuViewController?
private var isSideMenuPresented:Bool = false
private var isImageLoaded:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
self.isImageLoaded = false
self.setupUI()
self.delegate?.isImageLoaded(false)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "MainVC_SideMenuVC_Segue")
{
if let controller = segue.destination as? SideMenuViewController
{
self.sideMenuViewController = controller
self.sideMenuViewController?.delegate = self
}
}
}
/* ... */
//I'm using PHPicker, and when new image is selected, i want to send "true" via delegate
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true)
if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self){
let previousImage = self.presentedImage.image
itemProvider.loadObject(ofClass: UIImage.self){ [weak self] image, error in
DispatchQueue.main.async {
guard let self = self, let image = image as? UIImage, self.presentedImage.image == previousImage else {
return
}
self.presentedImage.image = image
self.isImageLoaded = true;
self.delegate?.isImageLoaded(true)
}
}
}
}
SideMenuViewController + SideMenuViewControllerDelegate
protocol SideMenuViewControllerDelegate{
func hideSideMenu()
func performAction(_ type:OperationType)
}
class SideMenuViewController: UIViewController {
/*...*/
var delegate: SideMenuViewControllerDelegate?
var mainViewController: MainViewController?
private var menuData: [ExpandingCellModel] = []
private var isImageLoaded: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// self.mainViewController?.delegate = self
menuData = setupData()
setupUI()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = segue.destination as? MainViewController {
controller.delegate = self
}
}
}
/* ... */
Here is what I think is happening.
There is segue happening from MainVC to SideMenuVC but there is no segue actually happening between SideMenuVC to MainVC in my opinion.
Happening is keyword because there is an EmbedSegue from MainVC to SideMenuVC but where is the segue from SideMenuVC to MainVC ? You did some connection in storyboard but nothing is happening in my opinion.
That is why in override func prepare is being called as planned in MainViewControllerDelegate and the delegate is getting set but it is not getting set in SideMenuViewController since override func prepare doesn't get called as no segue happens.
What you can do instead which might work is set both the delegates inside prepare in MainViewControllerDelegate
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "MainVC_SideMenuVC_Segue")
{
if let sideMenuVC = segue.destination as? SideMenuViewController
{
sideMenuVC.delegate = self
// assign MainViewControllerDelegate here
self.delegate = sideMenuVC
}
}
}
Check now if data is sent back to main view controller also.
If your issue is still not yet solved, please have a look and try this small example I set for you in github to show passing data between mainVC and embeddedVC and it might give you some hints.
You can see the result of this in action here: https://youtu.be/J7C7SEC04_E

Using functions from delegate in SwiftUIView

Quick question for anyone feeling up for helping a noob.
So I have a protocol in my main class that has a function that I'd like to access from a UIView. This works for other view controllers. However, in my prepare function, I try this:
if let destination = segue.destination as? SwiftUIView {
destination.delegate = self
}
But I get, "Cast from 'UIViewController' to unrelated type 'SwiftUIView' always fails"
and "Cannot assign to property: 'destination' is a 'let' constant".
This is my whole prepare function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ClientView
{
let vc = segue.destination as? ClientView
vc?.username = thetitle;
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
if let destination = segue.destination as? SwiftUIView {
destination.delegate = self
}
}
and it works in the CreateClientView. But not for my SwiftUIView. Any idea how to fix this? I am accessing the function in SwiftUIView the same way I do in CreateClientView. Thanks everybody.
SwiftUIView is just type View and looks like this (abridged):
struct SwiftUIView: View {
#State var username: String = ""
#State var address: String = "";
#State var notificationsEnabled: Bool = false
#State var note: String = "";
var delegate:ClientDelegate?;
and SwiftUIView is a child of another view which looks like this:
class CreateClientView: UIViewController {
let contentView = UIHostingController(rootView: SwiftUIView());
var delegate:ClientDelegate?;
var mainView : ViewController?;
override func viewDidLoad() {
super.viewDidLoad()
addChild(contentView);
view.addSubview(contentView.view);
setupConstraints()
// Do any additional setup after loading the view.
}
As the error message states, you're trying to cast a SwiftUI view into a ViewController. which you cant.
For a quick fix to your problem you can try this
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ClientView
{
let vc = segue.destination as? ClientView
vc?.username = thetitle;
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
}
class CreateClientView: UIViewController, SwiftUIViewDelegate {
let contentView = UIHostingController(rootView: SwiftUIView(delegate: self));
var delegate:ClientDelegate?;
var mainView : ViewController?;
override func viewDidLoad() {
super.viewDidLoad()
addChild(contentView);
view.addSubview(contentView.view);
setupConstraints()
// Do any additional setup after loading the view.
}
// MARK: SwiftUIViewDelegate
// call ClientDelegate here whereever SwiftUIViewDelegate methods are implemeted
}
protocol SwiftUIViewDelegate {...}
struct SwiftUIView {
let delegate: SwiftUIViewDelegate
}

Passing data forward from ViewController to ContainerView

I am using network request to retrieve data from back-end in ViewController and this view contains three containers so, I want to pass these data into containers. that fails while I am using prepare for segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ContinueSurvey" {
let continueSurveyVC = segue.destination as! ContinueSurveyVC
continueSurveyVC.notComplatedSurveies = notComplatedSurveies
} else if segue.identifier == "LatestOffers" {
let latestOffersVC = segue.destination as! LatestOffersVC
latestOffersVC.latestOffers = latestOffers
} else if segue.identifier == "LatestSurvey" {
let latestSurveyVC = segue.destination as! LatestSurveyVC
latestSurveyVC.latestSurveies = latestSurveies
}
}
This might help: https://learnappmaking.com/pass-data-between-view-controllers-swift-how-to/
Here’s a view controller MainViewController with a property called
text:
class MainViewController: UIViewController
{
var text:String = ""
override func viewDidLoad()
{
super.viewDidLoad()
}
}
Whenever you create an instance of MainViewController, you can assign
a value to the text property. Like this:
let vc = MainViewController()
vc.text = "Hammock lomo literally microdosing street art pour-over"
This is the code for the view controller:
class SecondaryViewController: UIViewController
{
var text:String = ""
#IBOutlet weak var textLabel:UILabel?
override func viewDidLoad()
{
super.viewDidLoad()
textLabel?.text = text
}
}
Then, here’s the actual passing of the data… Add the following method
to MainViewController:
#IBAction func onButtonTap()
{
let vc = SecondaryViewController(nibName: "SecondaryViewController", bundle: nil)
vc.text = "Next level blog photo booth, tousled authentic tote bag kogi"
navigationController?.pushViewController(vc, animated: true)
}
you can use present ViewController and in presented ViewController in viewWillAppear check what happened:
present VeiwController:
let vc = self.storyboard?.instantiateViewController(withIdentifier: "yourViewControllerIdentifire") as! yourViewController
self.present(vc, animated: true, completion: nil)
& in yourViewContriller use viewWillAppear to pass those data into containers:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//pass those data into containers
}
If you want to update child controllers when they already loaded, you need to store reference on them in parent controller and then in desire moment of time update data as:
weak var continueSurveyVC: ContinueSurveyVC?
weak var latestOffersVC: LatestOffersVC?
weak var latestSurveyVC: LatestSurveyVC?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ContinueSurvey" {
continueSurveyVC = segue.destination as! ContinueSurveyVC
continueSurveyVC?.notComplatedSurveies = notComplatedSurveies
} else if segue.identifier == "LatestOffers" {
latestOffersVC = segue.destination as! LatestOffersVC
latestOffersVC?.latestOffers = latestOffers
} else if segue.identifier == "LatestSurvey" {
latestSurveyVC = segue.destination as! LatestSurveyVC
latestSurveyVC?.latestSurveies = latestSurveies
}
}
/// Call this method anytime you want to update children data
func updateChildData() {
continueSurveyVC?.notComplatedSurveies = notComplatedSurveies
latestOffersVC?.latestOffers = latestOffers
latestSurveyVC?.latestSurveies = latestSurveies
}

How to call a function after performing a segue in swift?

Hello I want to know what is the best way to call a func after performing a segue on swift. I want to click on a button and perform a segue and start my viewDidLoad() with a new func.
//FIRST VIEW CONTROLLER
import UIKit
class CelebritiesViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
questionsLevel1()
pickingRandomQuestion()
hide()
finishGame.hidden = true
nextLevel.hidden = true
if isButtonClick == true {
questionsLevel2()
}
}
}
//SECOND VIEW CONTROLLER
import UIKit
class Level2Section: UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "level2" {
if let destinationLevel2 = segue.destinationViewController as? CelebritiesViewController {
destinationLevel2.isButtonClick = true
}
}
}
}
PS: After finish first section of questions user can choose to finish the game or go to next level, next level is a new view controller so we performing this segue in a second view controller not in the same one.
ViewController1:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueIdentifierHere" {
if let destVC = segue.destinationViewController as? ViewController2 {
destVC.isButtonClick = true
}
}
}
ViewController2:
Define a Bool:
var isButtonClick:Bool!
ViewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
questionsLevel1()//This is my first section of questions
pickingRandomQuestion()//My function to make a random number of questions
if isButtonClick == true {
isButtonClick = !isButtonClick
callSecondFunction()
}
}

Sending data with Segue with Swift

I have two view controllers and two views.
In my first view, I set the variable 'currentUser' to false.
I need to be able to set 'currentUser' to true in the second view controller.
When trying to reference 'currentUser' from the second view it's not picking it up as 'currentUser' is defined in the first view controller.
How do I carry across variables with segue?
Set values from Any ViewController to a Second One using segues
Like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "yourIdentifierInStoryboard") {
let yourNextViewController = (segue.destinationViewController as yourNextViewControllerClass)
yourNextViewController.value = yourValue
And in your yourNextViewController class.
class yourNextViewControllerClass {
var value:Int! // or whatever
You can call this also programmatically:
self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)
Set values from your DestinationViewController back to your Primary (First) ViewController
1. Implement a protocol, for example create a file called protocol.swift.
protocol changeUserValueDelegate {
func changeUser(toValue:Bool)
}
2. set the delegate on your second View
class yourNextViewControllerClass {
var delegate:changeUserValueDelegate?
3. set the delegate on load (prepareForSegue)
if(segue.identifier == "yourIdentifierInStoryboard") {
var yourNextViewController = (segue.destinationViewController as yourNextViewControllerClass)
yourNextViewController.delegate = self
4. add Function to FirstViewController
func changeUser(toValue:Bool) {
self.currentUserValue = toValue
}
5. call this function from your SecondViewController
delegate?.changeUser(true)
6. Set the delegate in your FirstViewController
class FirstViewController: UIViewController, ChangeUserValueDelegate {
The problem here is that your currentUser variable is of type Bool, which is a value type. So passing it from your first view controller to your second view controller will in fact create a new Bool instance. What you need is to pass a reference from your first view controller to your second view controller (see Value and Reference Types for more details on value and reference with Swift).
Thereby, according to your needs/preferences, you may choose one of the three following examples.
1. The boxing style
Here, we "box" our Bool inside a class and pass a reference of that class instance to the second view controller.
1.1. Create a CurrentUser class:
class CurrentUser {
var someBooleanValue = true {
didSet {
print(someBooleanValue)
}
}
}
1.2. Create a UIViewController subclass for the first view controller:
import UIKit
class ViewController1: UIViewController {
let currentUser = CurrentUser()
override func viewDidLoad() {
super.viewDidLoad()
currentUser.someBooleanValue = false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController2 = segue.destinationViewController as? ViewController2 {
viewController2.currentUser = currentUser
}
}
}
1.3. Create a UIViewController subclass for the second view controller:
import UIKit
class ViewController2: UIViewController {
var currentUser: CurrentUser?
// Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
#IBAction func toggleBoolean(sender: AnyObject) {
if let currentUser = currentUser {
currentUser.someBooleanValue = !currentUser.someBooleanValue
}
}
}
2. The closure style
Here, we get a weak reference of our first view controller in a closure and pass this closure to the second view controller.
2.1. Create a UIViewController subclass for the first view controller:
import UIKit
class ViewController1: UIViewController {
var currentUser = true {
didSet {
print(currentUser)
}
}
override func viewDidLoad() {
super.viewDidLoad()
currentUser = false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController2 = segue.destinationViewController as? ViewController2 {
let closureToPerform = { [weak self] in
if let strongSelf = self {
strongSelf.currentUser = !strongSelf.currentUser
}
}
viewController2.closureToPerform = closureToPerform
}
}
}
2.2. Create a UIViewController subclass for the second view controller:
import UIKit
class ViewController2: UIViewController {
var closureToPerform: (() -> Void)?
// Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
#IBAction func toggleBoolean(sender: AnyObject) {
closureToPerform?()
}
}
3. The protocol-delegate style
Here, we make our first view controller conform to some protocol and pass a weak reference of it to the second view controller.
3.1. Create a custom protocol:
protocol MyDelegate: class {
func changeValue()
}
3.2. Create a UIViewController subclass for the first view controller and make it conform to the previous protocol:
import UIKit
class ViewController1: UIViewController, MyDelegate {
var currentUser = true {
didSet {
print(currentUser)
}
}
override func viewDidLoad() {
super.viewDidLoad()
currentUser = false
}
func changeValue() {
currentUser = !currentUser
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController2 = segue.destinationViewController as? ViewController2 {
viewController2.delegate = self
}
}
}
3.3. Create a UIViewController subclass for the second view controller:
import UIKit
class ViewController2: UIViewController {
weak var delegate: MyDelegate?
// Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
#IBAction func toggleBoolean(sender: AnyObject) {
delegate?.changeValue()
}
}
Add an attribute currentUserSecondVC in the destination view controller, and use prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Name Of Your Segue" {
var vc = segue.destinationViewController as NameOfTheSecondViewController
vc.currentUserSecondVC = !currentUser //you can do whatever you want with it in the 2nd VC
}
}
The function that should be defined as override is:
open func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "Segue Name Defined In Storyboard") {
//set the property of the designated view controller with the value you need
}
}
Since you're using same variable across the two Viewcontrollers, namely currentUser (type Bool).
So its better to make it a global variable in both classes.
When coming to global variable concept in swift.
Everything by default in swift is public, and thus if you declare something like this:
class FirstViewController: UIViewController {
var someVariable: Boll = YES
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
You can access it and set values as long as you have an instance of it:
var MySecondViewController: FirstViewController = FirstViewController(nibName: nil, bundle: nil)
var getThatValue = MySecondViewController.someVariable

Resources