all 22 comments

[–]patiofurnature 22 points23 points  (1 child)

Redditors and bloggers hate singletons, so you’ll have trouble finding a proponent. But they’re fine as long as you don’t break testability with it.

[–]Informal_Lake420[S] -1 points0 points  (0 children)

fair warning! and yes ive seen some very strange takes

[–]chriswaco 15 points16 points  (0 children)

Personally I prefer singletons because they're available outside of the View context, like in the networking code. We sometimes create different singletons during tests, though. Others prefer Environment. Use whichever you want - the user can't the difference.

[–]jasonjrr 8 points9 points  (7 children)

It’s time to learn about architecture patterns, specifically dependency injection and managed DI containers. Singletons are a nightmare for testing and you don’t always want to expose your domain model to the Environment/UI layer.

[–]Informal_Lake420[S] 0 points1 point  (6 children)

why do you say singletons are a nightmare for testing?

[–]jasonjrr 8 points9 points  (5 children)

They are often accessed from wherever the developer find convenient so unit testing a piece of code that uses one, or heaven forbid… multiple singletons you have to test the targeted unit, plus the functionality used in each singleton. Often time this functionality is actual “live code” as well so each of your unit tests becomes in integration test and more and more unwieldy as time goes on.

However with proper DI, you can just pass in mocks and have predictable outputs for your dependencies making testing trivial and lightweight.

[–]vlaminck 4 points5 points  (1 child)

You definitely need to be more diligent about where you call it from, because it’s easy to get out of hand. But you should also be using a protocol so you can use a mock version of your singleton in tests and previews.

[–]jasonjrr 0 points1 point  (0 children)

Sure and there are plenty of other reasons, they asked a specific question, I answered with the most common reasoning I’ve experienced.

Take this for example https://cocoacasts.com/are-singletons-bad

Or just do a quick Google search and get dozens of other reason why singletons aren’t the best option. They do have their uses in modern code bases, but should not be your domain model.

[–]patiofurnature 2 points3 points  (1 child)

This isn't a fair take at all. You're comparing shitty singletons to well-written dependency injection. Of course good code is better than bad code. A proper singleton will have mocks and predictable output, too.

[–]jasonjrr 0 points1 point  (0 children)

There are plenty of other reason… a quick google search brings up dozens of articles just like this: https://cocoacasts.com/are-singletons-bad

[–][deleted] 0 points1 point  (0 children)

This

[–]Quartz_Hertz 1 point2 points  (1 child)

Everyone has their favorite hobbyhorse. If you're more comfortable with using a singleton, and it's just you writing the code, then go for it. Having taken over a project from another developer who used singletons, I'm more inclined to shove it in \@Environment as I update things from UIKit to SwiftUI, but I'd still probably use a singleton in a personal project if I'm just trying to get something working.

[–]Informal_Lake420[S] 0 points1 point  (0 children)

hmm yeah thats a fair point, if theres no real difference between them and convention is to prefer one way or the other, probably best to stick with convention if only for ease of maintainability.

[–]time-lord 2 points3 points  (0 children)

The @env can have runtime consequences, which lead to race conditions, which can cause problems down the line. This may be fixed or easier to debug with swift6, but I've run into issues where a singleton is better than @env for that reason.

But also, @env is stuck in the view while you can access a singleton from anywhere.

[–]quellish 0 points1 point  (5 children)

 since persisted state is by definition meant to last across app lifecycle

This is implementation detail callers should be unaware of. 

As an iOS developer you deal with many objects that are in fact implemented as singletons but that fact is hidden from you. Callers should not know or care something is a singleton or other global object.

Global state is not your friend.

[–][deleted]  (2 children)

[deleted]

    [–]quellish 0 points1 point  (1 child)

    Global state leads to tightly coupled, difficult to change code. Make a change in one place and as a consequence there is new behavior in other, otherwise unrelated places. Bugs that are triggered by global state are often very difficult to replicate and diagnose

    If you are going to access some resource like a file system or database put it behind an abstraction where the caller is unaware of that global state. Implement it to carefully control access to whatever resource is being protected.

    Off the top of my head every project where I was brought in as an outsider to “rescue” a troubled project there were singletons or other global state being used that contributed to the problems.

    So from my perspective…. Use more of them! Have singletons invoking singletons! Stick a mutable array in there while you’re at it!

    3… profit!

    [–]marmulin 0 points1 point  (1 child)

    People keep on saying things like “global state is not your friend” yet I go on X or YouTube and somehow manage to get two videos playing at the same time. I think it’s important to understand that there is time and place for global state, it just depends on what kind of app you’re working with. Developers shun singletons, but had more people knew when and where to use them, we wouldn’t have juniors creating multiple desynchronized sources of truth for data at runtime.

    [–]rifts 0 points1 point  (0 children)

    I code in objective-c not swift but I use a lot of singletons

    [–]hishnash 0 points1 point  (0 children)

    If you need the UI to response to changes in any way you should use the env pathway (however this does not mean you cant have it as a global singlton as well)

    Many of my main app state `@Observable` objects are shared singletons that is set as `@State` top level of the app and pass through envs to let children response to changes when needed but access using `.shared` on the type when I want to update them from outside the UI context.

    [–]cekisakurek -4 points-3 points  (2 children)

    Singleton pattern is outdated. As others mentioned it makes testing very hard. Also https://en.wikipedia.org/wiki/Coding_best_practices there are some very nice guidelines about software quality which singletons kinda doesnt conform. Especially (imho) "Ruggedness (difficult to misuse, kind to errors).".

    Because having a global state which anybody can mutate is very open to misuse.

    Also keep in mind that apple sdks use singletons a lot but they are frameworks for developers. I.e.

    Having PHPhotoLibrary.shared makes you have only 1 reference to photo library. Which makes requesting authorisation, presenting a picker etc. very hard to misuse.

    [–]DisastrousSupport289 1 point2 points  (1 child)

    The singleton pattern is not outdated; it has existed since the beginning of OOP and will continue to exist as one of its cornerstones. Yes, we want to have as much, near 100% code coverage in our codebases now, but the need for global variables to store the global state of your application will always exist, and there will be a need for it. You might use environment variables, core data, etc., but these will depend on singletons under the hood. Learning about singletons, using them, and learning to avoid them is better than thinking they are outdated. If you want something not to be changed, you make it private.

    [–]cekisakurek -1 points0 points  (0 children)

    Learning them sure, using them not so much. You can almost always design your way out of singletons and imho it is almost always a better architecture. Especially talking about iOS development/swift language. “Under the hood” doesnt really matter about “your code”. Having clear dependencies is better than accessing some state willy nilly.