Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any reason not use use a singleton "variable" in Swift?

For Sept 2015, here's exactly how you make a singleton in Swift:

public class Model
    {
    static let shared = Model()
    // ( for ocd friends ... private init() {} )
    
    func test()->Double { print("yo") }
    }

then elsewhere...

blah blah
Model.shared.test()

No problem.

However. I add this little thing...

public let model = Model.shared
public class Model
    {
    static let shared = Model()
    
    func test()->Double { print("yo") }
    }

then, you can simply do the following project-wide:

blah blah
model.test()

Conventional idiom:

You see Model.shared.blah() everywhere in the code.

"My" idiom:

You see model.blah() everywhere in the code.

So, this results in everything looking pretty!

enter image description here

This then, is a "macro-like" idiom.

The only purpose of which is to make the code look pretty.

Simplifying appearances of ImportantSystem.SharedImportantSystem down to importantSystem. throughout the project.

Can anyone see any problems with this idiom?

Problems may be technical, stylistic, or any other category, so long as they are really deep.

As a random example, here's an "article in singletons in Swift" that happens to also suggest the idea: https://theswiftdev.com/swift-singleton-design-pattern/

like image 389
Fattie Avatar asked Sep 18 '15 20:09

Fattie


3 Answers

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).

like image 81
Rob Avatar answered Nov 09 '22 01:11

Rob


There are a few things to look out for when using this approach:

The global variable

A global variable in itself is no big deal, but if you have quite some global variables, you might have trouble with autocompletion, because it will always suggest these global variables.

Another problem with global variables is that you could have another module in your application (written by you or otherwise) define the same global variable. This causes problems when using these 2 modules together. This can be solved by using a prefix, like the initials of your app.

Using global variables is generally considered bad practice.

The singleton pattern

A singleton is helpful when working with a controller, or a repository. It is once created, and it creates everything it depends on. There can be only one controller, and it opens only one connection to the database. This avoids a lot of trouble when working with resources or variables that need to be accessed from throughout your app.

There are downsides however, such as testability. When a class uses a singleton, that class' behaviour is now impacted by the singletons behaviour.

Another possible issue is thread safety. When accessing a singleton from different threads without locking, problems may arise that are difficult to debug.

Summary

You should watch out when defining global variables and working with singletons. With the appropriate care, not many problems should arise.

like image 39
vrwim Avatar answered Nov 09 '22 00:11

vrwim


I can't see a single downside to this approach:

  • You can use different variables for different parts of the program (-> No namespace cramming if you don't like this I guess)
  • It's short, pretty, easy to use and makes sense when you read it. Model.shared.test() doesn't really make sense if you think about it, you just want to call test, why would I need to call shared when I just need a function.
  • It uses Swift's lazy global namespace: The class gets allocated and initialized when you use it the first time; if you never use it, it doesn't even get alloced/inited.

In general, setting aside the exact idiom under discussion, regarding the use of singletons:

  • Recall that, of course, instead of using static var shared = Model() as a kind of macro to a singleton, as suggested in this Q, you can just define let model = Model() which simply creates a normal global (unrelated to singletons).
  • With Swift singletons, there has been discussion that arguably you want to add a private init() {} to your class, so that it only gets initialized once (noting that init could still be called in the same file).
  • Of course in general, when considering use of a singleton, if you don't really need a state and the class instance itself, you can simply use static functions/properties instead. It's a common mistake to use a singleton (for say "calculation-like" functions) where all that is needed is a static method.
like image 20
Kametrixom Avatar answered Nov 09 '22 01:11

Kametrixom