Search code examples
swiftsingletonvalue-typereference-type

Assigning values to properties in a singleton implemented with static let in Swift


From reading it seems like the best advice for creating a singleton in Swift is to use static let like this:

struct GameManager {
  static let defaultManager = GameManager()
  var gameScore = 0
  var saveState = 0
  private init() {}
}

GameManager.defaultManager.gameScore = 1024 // Error
GameManager.defaultManager.saveState = 12 // Error
let score = GameManager.defaultManager.gameScore
let savedProgress = GameManager.defaultManager.saveState

Because the defaultManager is declared as a constant (with "let"), there is an error when I try to assign gameScore and saveState.

playground error cannot assign to property

I'm running Xcode 7.0 beta 6 (7A192o) with Swift 2.0 (swiftlang-700.0.57.3 clang-700.0.72).

If I change the defaultManager to be declared as a variable (with "var"), will it no longer be considered a proper singleton?


If I change the GameManager to be declared as a class instead of a structure, then the code works as expected.

class GameManager {
  static let defaultManager = GameManager()
  var gameScore = 0
  var saveState = 0
  private init() {}
}

GameManager.defaultManager.gameScore = 1024 // No error, why?
GameManager.defaultManager.saveState = 12 // No error, why?
let score = GameManager.defaultManager.gameScore // 1,024
let savedProgress = GameManager.defaultManager.saveState // 12

Can you explain why the reference-type class is better for implementing the singleton than the value-type structure?


Solution

  • You can't really change it because on your struct you have a let constant named defaultManager. As you know already a struct is a copy type while a class is a pass by reference one. if you want to use it as a struct you will have to replace that let with var instead. Another take of this problem is to change the struct to a class that way you will be able to change the defaultManager value although it is declared as a let.

    cheers

    edit: The main difference in your code is that when you have a constant in a class and you change that constant you are actually referring to its address rather than its actual value.Same doesn't happen with a struct cause as a value type you can't do that call by reference thingy you do with class and so you are forced to have a constant(let) value that cannot be mutated. Change the let to var inside your struct and see the magic happen