Global Var VS Shared Instance Swift

How to use sharedInstance on swift as global variable?

If it isn't a lot of data, the strategy I use to pass data between view controllers is to store the value in NSUserDefaults.

Setting A Value: When you first get the data, store it in NSUserDefaults.

let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults() //This class variable needs to be defined every class where you set or fetch values from NSUserDefaults
defaults.setValue(42, forKey: "userID")
defaults.setValue("too", forKey: "username")
defaults.synchronize() //Call this when you're done editing the defaults. It saves your changes to the disk

Fetching A Value: When you need to get the values, just grab it from NSUserDefaults.

let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
let userID = defaults.objectForKey("userID") as? Int
let username = defaults.objectForKey("username") as? String

Doing that gives you access to the stored values in any class and allows the data to persist after the app is closed and reopened. If you want to clear the data after the app closes, in AppDelegate applicationWillTerminate(application: UIApplication) function, call the removeObjectForKey function for each key previously set.

let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
defaults.removeObjectForKey("userID")
defaults.removeObjectForKey("username")
defaults.synchronize()

Helpful Source on NSUserDefaults:

NSUserDefulats Class Reference: Link here.

Any reason not use use a singleton variable in Swift?

Functionally, these are very similar, but I'd advise using the Model.shared syntax because that makes it absolutely clear, wherever you use it, that you're dealing with a singleton, whereas if you just have that model global floating out there, it's not clear what you're dealing with.

Also, with globals (esp with simple name like "model"), you risk of having some future class that has similarly named variables and accidentally reference the wrong one.

For a discussion about the general considerations regarding globals v singletons v other patterns, see Global Variables Are Bad which, despite the fairly leading title, presents a sober discussion, has some interesting links and presents alternatives.


By the way, for your "OCD friends" (within which I guess I must count myself, because I think it's best practice), not only would declare init to be private, but you'd probably declare the whole class to be final, to avoid subclassing (at which point it becomes ambiguous to what shared references).

Swift - What is a better alternative to Global Variables?

The problem you are facing is that global variables, in and of themselves, are often considered a code smell.

Essentially, you are saying "I like <code smell> but my code analyzer is flagging it as a code smell."

Have you considered making your manager objects singletons? Consider the pattern Apple uses for things like UserDefaults (a class var standard that returns the shared UserDefaults object.)

Edit:

Rereading your question, I guess that's what you are suggesting in form B. That makes the static var a class variable of the class, and turns the object into a singleton. It's not quite the same thing as a global.

When to use global variables in Swift

Every time you find yourself using a global, you need to take a step back and think hard about what the data is and how it relates to the rest of your app. It is easy to say you need to avoid globals, the hard part is knowing the best alternative for the scenario, something even veteran Cocoa developers will disagree on.

In the singleton pattern, you create a class and stash your global inside it. This is often offered as a solution because it's the easiest to prescribe and follow, but many times I wonder if it is a solution at all. Wrapping a class around a global doesn't give you any additional protections. After all, the class itself is now a global entity. I like to think of the Singleton pattern as a way of organizing, categorizing and containing globals as opposed to avoiding globals.

Singletons should be reserved for the tentpoles of your application like database or remote backend connection handlers. Every Cocoa/CocoaTouch App comes with a built in Singleton, the AppDelegate, and in many cases, assorted things can go there.

In many cases, the "correct" solution is to pass the data along, such as passing data between view controllers in the prepareForSegue: class. This is well described in Andy Matuschak's brilliant WWDC 2014 session, Advanced iOS Application Architecture and Patterns. I agree with you though, that this doesn't apply in your example. In your example, you're not handing relevant data between two views, you're trying to share a common facility to conserver resources.

For your specific example, I would use a Singleton or similar pattern. One way that makes sense to me is to stash them inside their corresponding classes using extensions. For example:

extension NSDateFormatter {
static let newDateFormatter = NSDateFormatter()
}

// use it in your app like this:
NSDateFormatter.newDateFormatter

Like commenters said, this is a matter of opinion. Also keep in mind that Swift is still young and while it borrows heavily from Cocoa out of necessity, idioms are still evolving.

How is a global variable set to private understood in swift?

A private global variable in Swift is a global that is only accessible from the file in which it is declared.

The book you are using isn't following current best-practice as far as creating singletons in Swift (perhaps it is a little out-dated?).

There is no need for the private global variable. You can just say:

class CDHelper: NSObject {
// MARK: - SHARED INSTANCE
static let shared = CDHelper()
}

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.

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.



Related Topics



Leave a reply



Submit