16

I tried creating global variables and updating the information when the view is loaded but data isn't being rendered.

GLOBAL VARIABLES

var viewName:String = ""
var viewDuration:String = ""
var viewPeriod:String = ""
var viewMinAmp:String = ""
var viewMaxAmp:String = ""
var viewStep:String = ""
var viewType:String = ""

Is there a more efficient way of passing information other than having global variables?

@IBOutlet var txtName: UITextField!
@IBOutlet var txtDuration: UITextField!
@IBOutlet var txtPeriod: UITextField!
@IBOutlet var txtMinAmp: UITextField!
@IBOutlet var txtMaxAmp: UITextField!
@IBOutlet var txtStep: UITextField!
@IBOutlet var txtType: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    setInfo(viewName, duration: viewDuration, period: viewPeriod, minAmp: viewMinAmp, maxAmp: viewMaxAmp, step: viewStep, type: viewType)
}

func setInfo(name: String, duration: String, period: String, minAmp: String, maxAmp: String, step: String, type: String) {
    txtName.text = name
    txtDuration.text = duration
    txtPeriod.text = period
    txtMinAmp.text = minAmp
    txtMaxAmp.text = maxAmp
    txtStep.text = step
    txtType.text = type
}
Juan Boero
  • 6,281
  • 1
  • 44
  • 62
Tomasero
  • 567
  • 3
  • 5
  • 12
  • 4
    Define properties in UIViewControllers and set them when initializing that controller. Don't use global variables, its a bad practice here. – AndrewShmig Aug 09 '14 at 05:28
  • How do I access methods from a controller from another controller? @AndrewShmig – Tomasero Aug 10 '14 at 18:17
  • how do you access other methods in Swift? :) – AndrewShmig Aug 10 '14 at 20:03
  • possible duplicate of [How do you share data between view controllers and other objects in Swift?](http://stackoverflow.com/questions/29734954/how-do-you-share-data-between-view-controllers-and-other-objects-in-swift) – nhgrif Jun 19 '15 at 14:25
  • See [this answer](http://stackoverflow.com/a/31934786/3681880) for a basic example. – Suragch Aug 11 '15 at 06:38

5 Answers5

34

One solution would be to override prepareForSegue(segue:sender:) from within the view controller which contains the data that you wish to pass to the destination view controller.

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if (segue.identifier == "YourSegueName") {
        //get a reference to the destination view controller
        let destinationVC:ViewControllerClass = segue.destinationViewController as! ViewControllerClass

        //set properties on the destination view controller
        destinationVC.name = viewName
        //etc...
    }
}
Scott Mielcarski
  • 760
  • 6
  • 17
  • 1
    does this work in Swift 2.1 ? I used exact same code and I get "Cannot convert value of type UIViewController to specified type NextViewController" – Deepak Thakur Dec 23 '15 at 11:07
  • I haven't tried it in Swift 2.1 yet; however, it sounds like you may need explicitly cast the destination view controller. `let destinationVC:ViewControllerClass = segue.destinationViewController as ViewControllerClass` – Scott Mielcarski Dec 24 '15 at 18:26
  • This still needs the use of Global variables. Any ideas on how to avoid global variables for passing data between view controllers or rather avoid shared state – Pradeep Banavara Apr 07 '16 at 09:12
  • Why does creating a copy of the `ViewControllerClass` change the properties of the real thing? – Declan McKenna Jul 11 '17 at 08:40
24

For Swift 3.0

final class Shared {
     static let shared = Shared() //lazy init, and it only runs once

     var stringValue : String!
     var boolValue   : Bool!
}

To set stringValue

Shared.shared.stringValue = "Hi there"

to get stringValue

 if let value = Shared.shared.stringValue {
        print(value)
 }

For Swift version below 3.0

You can pass data between views using singleton class. It is easy and efficient way. Here is my class ShareData.swift

import Foundation

class ShareData {
    class var sharedInstance: ShareData {
        struct Static {
            static var instance: ShareData?
            static var token: dispatch_once_t = 0
        }

        dispatch_once(&Static.token) {
            Static.instance = ShareData()
        }

        return Static.instance!
    }


    var someString : String! //Some String

    var selectedTheme : AnyObject! //Some Object

    var someBoolValue : Bool!
}

Now in my ViewControllerOne I can set above variable.

//Declare Class Variable

let shareData = ShareData.sharedInstance

override func viewDidLoad() {
    self.shareData.someString ="Some String Value"
}

And in my ViewControllerTwo I can access someString as

let shareData = ShareData.sharedInstance
override func viewDidLoad() {
    NSLog(self.sharedData.someString) // It will print Some String Value
}
Saqib Omer
  • 5,387
  • 7
  • 50
  • 71
  • this is just a new blank project – iEmad Apr 07 '15 at 06:11
  • This sounds the right approach specially if instance is of something unique in the application for example userInfo, only one use can be logged in at a time and so can be a shared singleton instance. – adubey Mar 02 '16 at 17:39
  • I like this way to share data between controller! But since swift3.0 has many changes in grammar. Could you please update a swift3.0 version on this?@SaqibOmer – Nevermore Oct 03 '16 at 21:52
  • Am getting error on line: " static var token: dispatch_once_t = 0 " " 'dispatch_once_t' is unavailable in Swift: Use lazily initialized globals instead" – PhilipS Jan 31 '17 at 09:03
  • @PhilipS Which version of Swift you are using? And what is error? – Saqib Omer Jan 31 '17 at 09:06
  • @SaqibOmer Hi, I am using Swift 3. The error message is - dispatch_once_t' is unavailable in Swift: Use lazily initialized globals instead – PhilipS Jan 31 '17 at 10:55
  • @PhilipS Use Code For Swift 3 which is at top of my answer. You are using wrong code. – Saqib Omer Jan 31 '17 at 11:15
  • @SaqibOmer Thank you. Works great for passing Strings. But what is the syntax for passing Double. e.g. instead of "if let value = Shared.shared.stringValue". – PhilipS Jan 31 '17 at 12:13
  • @PhilipS .stringValue is just a variable. Declare a double in class as var someDouble : Double! and access that any where as Shared.shared.someDouble. – Saqib Omer Jan 31 '17 at 12:17
5

Personally, I prefer ways as follow:

  • If you want to jump forward between two view controllers (from A to B), as -pushViewController:animated: in navigation, you can define a property of model for Controller B and expose it publicly, then set this property explicitly before jumping from Controller A, it's pretty straightforward;

  • In case you want to jump backward from Controller B to A, use Delegate+Protocol mode. Controller B drafts a public protocol and own a "delegate" property, any object who would like to be the delegate of Controller B shall comply and implement its protocol(optionally). then prior to the jumping-backward, Controller B makes its delegate perform certain action(s) listed in protocol, the data could be transferred in this way;

  • Under certain circumstance, you may want to transfer data from a Controller(or controllers) to other multiple Controllers, use Notification mechanism if this is the case.

Apple has detailed instructions about delegate mode, notification mode in official documentation, check them out in XCode, :)

Ke Yang
  • 881
  • 1
  • 12
  • 21
1

Just need to follow 3 steps, let's assume you want to pass data from ViewControllerA to ViewControllerB:

  1. create a segue between ViewControllerA and ViewControllerB
  2. name the segue with a Identifier in the attributes inspector of it
  3. override the prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) at ViewControllerA

For step#3,:

  • if you are not using swift 2.1, please follow @Scott Mielcarski 's answer at this question
  • for people who are using swift 2.1, or who get error "Cannot convert value of type 'UIViewController' to specified type 'your view Controller class name', After following @Scott Mielcarski 's answer at this question, Please use:let destinationVC:ViewControllerClass = segue.destinationViewController as! ViewControllerClass instead of let destinationVC:ViewControllerClass = segue.destinationViewController

    This is tested on Swift 2.1.1 and it works for me.

Community
  • 1
  • 1
Byron Luo
  • 11
  • 2
0

If you don't actually want to pass data between view controllers but rather simply want to store a global variable you can do this:

This gives a great explanation for how to do this in Swift 5: https://www.hackingwithswift.com/example-code/system/how-to-save-user-settings-using-userdefaults

Summary:

To set a value:

let defaults = UserDefaults.standard
defaults.set("value", forKey: "key")

To get a String value:

let key = defaults.object(forKey: "StringKey") as? [String] ?? [String]()

To get integer value:

let key = defaults.integer(forKey: "IntegerKey")
Jeffrey Kozik
  • 201
  • 4
  • 8