Accessing Global Variable in Swift

How to create a global variable?

From the official Swift programming guide:

Global variables are variables that are defined outside of any
function, method, closure, or type context. Global constants and
variables are always computed lazily.

You can define it in any file and can access it in current module anywhere.
So you can define it somewhere in the file outside of any scope. There is no need for static and all global variables are computed lazily.

 var yourVariable = "someString"

You can access this from anywhere in the current module.

However you should avoid this as Global variables are not good for application state and mainly reason of bugs.

As shown in this answer, in Swift you can encapsulate them in struct and can access anywhere.
You can define static variables or constant in Swift also. Encapsulate in struct

struct MyVariables {
static var yourVariable = "someString"
}

You can use this variable in any class or anywhere

let string = MyVariables.yourVariable
println("Global variable:\(string)")

//Changing value of it
MyVariables.yourVariable = "anotherString"

Accessing global variable in Swift

I created a project in Xcode, a console application, the target is here a module.
So I named the project test and the target has the same name so in the project the module itself has also the name test. Any global definition will be implicit a call to test. . Just like the global Swift functions are implicit a call to Swift., like Swift.print("...").

var a = 10;

func foo() -> Int {
let a = 20;
Swift.print(test.a) // same as print(test.a)

return a;
}

test.foo() // same as foo()

Output is:

10


So you have to add the module name before the variable to get the global one and not the local one overshadowing it.

Swift Global Variables

You shouldn't use global variables, I don't think that's recommended in any language.

Now here you have what looks like a Singleton class (BroadService), that's good because it's a nice solution for what you're looking for.

Next all you need to do is add a property to that class. Let's say videoLink is a string, you can add a string property to BroadService, for example storedVideoLink as an optional String, and the next time you need to obtain that value after you have already fetched it, you can access it like so: BroadService.sharedInstance.storedVideoLink.

One more thing, to have BroadService work properly as a singleton, you should make its init private.

To sum up, here's what I'm suggesting:

class BroadService {
static let sharedInstance = BroadService()
var storedVideoLink: String?

private init() {} // to ensure only this class can init itself

func fetchBroadcasts(completion: @escaping ([Games]?) -> ()) {
// your code here
}
}

// somewhere else in your code:
BroadService.sharedInstance.fetchBroadcasts { (games) in
if let games = games {
let game = games[indexPath]
let videoLink = game.videoLink
BroadService.sharedInstance.storedVideoLink = videoLink
}
}
// now you can access it from anywhere as
// BroadService.sharedInstance.storedVideoLink

This way it all stays cohesive in the same class. You can even add a getter method for storedVideoLink so you don't have to access it directly, and in this method you could state that if the string is nil then you fetch the data, store the link to the string, and then return the string.

Creating a global variable in swift

I ended up following holex's suggestion of creating a shared class (singleton):

import UIKit
class ModelData: NSObject {
static let shared: ModelData = ModelData()
var name = "Fred"
var age = 50
}

Writing in first view: Set age to 51:

ModelData.shared.age = 51

Reading in second view: Get age of 51

let age = ModelData.shared.age

Is there a way to have a global variable between a SwiftUI view and classes indirectly related to it?

To make changes in a SwiftUI view, as it is a static element because of its struct declaration, your object GlobalString must conform to a StateObject to be able to make changes in real-time to a view, and its variables must conform to @Published.

class GlobalString: ObservableObject {
@Published var stringy = ""
@Published var temperature = 0.0
}

struct ContentView: View {

@StateObject var globalString = GlobalString()

var body: some View {
VStack {
Text(globalString.stringy)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}.onAppear {
k.start()
}
}
}

Is it good practice to use global variables and constants? (Swift 5)

You can use a static variable of a struct to do this more elegant:

struct Repository {
static var googleUser: String?
}

and access/set googleUser using the struct type:

Repository.googleUser = user

Or even better, use a singleton class like this:

class Repository {
static let shared = Repository()
var googleUser: String?
}

then you can use it directly:

Repository.shared.googleUser = user

or inject the singleton instance to whichever class want to use googleUser.

How use global Variables in views and classes?

Regarding your (second) question in your comment,
here is some code that shows an approach to "send" a value from a
class (does not have to be a view) and receive that value in a View.

You could use this approach in your "ts28bControllerDelegate",
to send the temperature updates as they arrive in your ts28bControllerDelegate and
receive them in your views using .onReceive(...)

public func controller(_ controller: TS28BController?, device: TS28B?, didUpdateTemperature value: Float, temperatureUnit unit: TemperatureUnit, measure date: Date?, measureLocation type: TemperatureType) {
print("Temperature UNIDAD:", unit)
print("Temperature:", value)
let valueFinal = ((value - 32) * 5/9)
let stringFloat = String(valueFinal)
// send a message with the temp value
NotificationCenter.default.post(name: GlobalTs28b.globalMsg, object: stringFloat)
}

class GlobalTs28b: ObservableObject {
@Published var temp: String = "----"
@Published var state: String = "----"

// for testing, does not have to be in this class
static let globalMsg = Notification.Name("GlobalTs28b")
}

struct ContentView: View {
@StateObject var global = GlobalTs28b() // for testing

var body: some View {
NavigationView {
VStack (spacing: 55) {
NavigationLink("go to next view", destination: ViewTest2())
Text(global.temp).foregroundColor(.red)
}
.onReceive(NotificationCenter.default.publisher(for: GlobalTs28b.globalMsg)) { msg in
if let temp = msg.object as? String {
// update the StateObject with the new info, so the view will update
global.temp = temp
}
}
}.navigationViewStyle(.stack)
}
}

struct ViewTest2: View {
var body: some View {
VStack {
Button(action: {
// send a message to all listeners with the new temp,
// could be used in any class such as ts28bControllerDelegate
NotificationCenter.default.post(name: GlobalTs28b.globalMsg, object: "new temp")
}) {
Text("click to update temp")
}
}
}
}

Declaring a global variable in swift while using UITableView

As the other posters have mention using global variables is not the best idea. It's not good coding practice, and can become very confusing once your app scales. When passing information between a TableView and another View (a ViewController, a Cell etc.) you have two options (not including using global variables).

First option: Use prepareForSegue

On your destination ViewController you need to create a variable called chosenFeed. Then at the bottom of your TableView you can use this prepareForSegue function to pass the data:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
if let destinationVC = segue.destinationViewController as ViewController {
destinationVC.chosenFeed = self.chosenFeed
}
}

OR You could use didSelectRowAtIndexPath

If this data needs to be sent and is based on which cell is selected you can use didSelectRowAtIndexPath. You still need to add on your destination ViewController a variable called chosenFeed. If you choose this option you also need to name your segue in the Storyboard.

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

// Youll need the name of your ViewController here to pass the variable
let destinationVC = "nameOfTheDestination_VC()"
destinationVC.chosenFeed = self.chosenFeed

//This is where you use the named segue from the Storyboard
destinationVC.performSegueWithIdentifier("segueName", sender: self)

}

Either of those suggestions should be what you're looking for. If after all that, you still decide you need a global variable (after all this was the question asked) you just need to declare the variable above the class declaration:

var chosenFeed : String? 
class About_VC: UIViewController {
//code here
}

One last note, from the example pictures you posted be careful with force unwrapping. Cheers!

Global Variable in Swift

You can put the variable in your AppDelegate, which is a singleton. See this post for how to access the AppDelegate

How do I get a reference to the app delegate in Swift?



Related Topics



Leave a reply



Submit