12

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/

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • Hi Glyuck. I agree with you, it is "bitchin'". However since (very surprisingly) I do not see it actually anywhere in a survey of the literature, we need to consider any potential downsides. – Fattie Sep 18 '15 at 20:42
  • 3
    I'm totally confused. Why would you have a global instance of a singleton? A global will work, a singleton will work... WTF is a global instance of a 'singleton'? – Grimxn Sep 18 '15 at 21:17
  • 1
    Hi Grim: thanks for your comment. Now, the variable "model" (the global one) simply points to Model.shared. Here's a clarifying example: in any class you could, for the hell of it, have a=Model.shared, b=Model.shared and c=Model.shared. You could do that (for no reason at all) and then you could use any of those variables, exactly where you would use "Model.shared". (There would be absolutely no reason to do this, other than it's shorter to type "a" than to type "Model.shared" ...!) Similarly here, "model" is basically like a macro for Model.shared. It makes code cleaner, eleganter. – Fattie Sep 18 '15 at 21:28
  • I really like this approach. And I think I am going to steal it :-) – Luca Angeletti Sep 23 '15 at 13:36
  • HI appz :) Yes, if you're say a game engineer, if you work on tools for big games, it is natural. You inevitably have singletons for things like "the AI system" or more prosaically "the scores", not to mention networking etc. Of course, with physical devices everything is a singleton (the compass, the gps, the sensors, the screen, etc etc etc) which is why everything from Apple is a singleton in iOS; in the same way there are always a few things which are singletons in games; you often use a similar macro or whatever so you can just type one word for those things. HOWEVER.... – Fattie Sep 23 '15 at 13:40
  • ...HOWEVER i agree 1000% with Rob's critical point if you careful read his answer. My central programming philosophy is "code should be self documenting" so you should have **utterly apparent** naming. Something I would say unto you, @appzForLife, if you do do this then use a REALLY OBVIOUS name. (Of course, that applies to every single variable or method you ever write in your life.) So, something like "theOneWordMacroForTheAISingleton" would be good! nameSingleton is a good choice. That would look great in code. `feedSingleton.latestData()` is better than `feed.latestData()` – Fattie Sep 23 '15 at 13:42
  • @Grimxn define each instance of singleton in class / viewcontroller can increase memory usage. – TomSawyer Apr 28 '16 at 09:42

3 Answers3

12

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

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 5
    There is fixing bugs .. there is actual engineering .. and above that, there is Rob ;) – Fattie Sep 23 '15 at 13:52
  • Reviving this old discussion because of a link from https://stackoverflow.com/q/57188218/97337, but agreed w/ @Rob here. There's no need for special candy; `Model.shared` is ideal. If you have a desire for a `model` syntax, I'd do that locally as `let model = Model.shared`. I often use that with a default parameter in `init` in order to make things more testable, while still supporting the common case of using the shared instance. But I wouldn't create a global variable called "model". – Rob Napier Jul 24 '19 at 18:05
3

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.

vrwim
  • 13,020
  • 13
  • 63
  • 118
2

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.
Fattie
  • 27,874
  • 70
  • 431
  • 719
Kametrixom
  • 14,673
  • 7
  • 45
  • 62
  • @JoeBlow Changed "exactly" to "basically" because yeah it's not exactly the same, however I cannot think of a way in that using `model` would differentiate using the two approaches – Kametrixom Sep 18 '15 at 22:22
  • @JoeBlow Also removed the static function code to make it less prominent :) – Kametrixom Sep 18 '15 at 22:25
  • 1
    @JoeBlow I guess you're right with the method you're using, if you somehow decided to make multiple global variables, they'd all still be the same instance. Btw really no need for bounty ;) – Kametrixom Sep 18 '15 at 22:27
  • 1
    @Rob Whops, I made such a bad mistake, I declared the variable in the main file *headpalm* (editing) – Kametrixom Sep 18 '15 at 22:42
  • 1
    I clicked the token bounty to Kamet's excellent and highly informative answer since, well, Rob is on a whole other level and doesn't need bounties any more :) *(For me it's [really a shame](http://meta.stackoverflow.com/questions/306275/add-reward-user-button-like-on-answers-unity-for-example) you can't simply click over as many bounties as you wish on this site, but that's life.)* Thanks men for your thoughts on this for me critical engineering issue. We are all part of a web of, err, focus that results in today's world around us. Discussions here affect millions. Yeah! :) – Fattie Sep 23 '15 at 13:50
  • @JoeBlow Wow, thank you! Yes, StackOverflow is very nice and I'm using it everyday; it's awesome to life in such a world :D Good day, Sir *shortly lifts his hat* – Kametrixom Sep 23 '15 at 14:25
  • @JoeBlow \*gets annoyed over that \* has to be escaped\* – Kametrixom Sep 23 '15 at 14:34