Nikita Vlasenko
Nikita Vlasenko

Reputation: 4352

Swift: refactor singleton pattern

I have a Swift singleton class that maintains app state by storing several arrays. What is the best practices' way to go here? Should we change it, and if we do, then how?

Here is the singleton class:

import Foundation


class FilterModel {
  static let sharedInstance = FilterModel()
  private init() { }

  var muscleExercisesArray = [Int]()
  var equipmentExercisesArray = [Int]()
  var typeExercisesArray = [Int]()
}

Upvotes: 2

Views: 337

Answers (1)

Rob
Rob

Reputation: 437552

If you're wondering about the basic singleton pattern, a couple of observations:

  1. I might suggest you declare the class to be final, too, to avoid having some future developer subclass it and introduce confusion about to what type sharedInstance refers.

  2. I might also suggest that in Swift 3, the convention is to simplify the name of sharedInstance to just shared. It's not a hard and fast rule, but is the emerging standard.

  3. This implementation is not thread-safe. If you're ok with that, I'd at least include some warning in the comments warning future developers of this concern. Or, obviously, with a little work you could change this to be thread-safe by wrapping this all in some internal synchronization mechanism.


You said:

Singletons are considered a bad approach towards app architecture, so I was wondering what to do instead of it when we need to maintain app state. Somehow I can not find anything online except for DI approach that does not work (or I do not know how) in this case when we need app state to be modified by different files

Yes, singletons are not ideal for model objects for a number of reasons (makes unit testing harder; makes responsibilities unclear, etc.) and there are better patterns (see What's Alternative to Singleton). At the very least, one simple approach is to have app delegate or root view controller instantiate this model object and then only pass this to whatever subsequent controllers need access to it (e.g. in prepareForSegue). This way, it's explicit which objects might be interacting with the model, making responsibilities a little more clear.

Upvotes: 3

Related Questions