Search code examples
swiftmemorymodelreferencesolution

How can I change an object reference to a new object that has implemented the same protocol in swift?


I want to have a global settings model and change it at runtime. Unfortunately my view models hold the reference of the old global settings model. My complex solution is to update all view models again with the new settings model. Is there a better solution? Here is my sample code that does not work. My intention was that the third output is "Inch".

protocol SettingsModelProtocol {
    var unit: String { get set }
}

class MetricSettingsModel: SettingsModelProtocol {
    var unit: String = "cm"
}

class ImperialSettingsModel: SettingsModelProtocol {
    var unit: String = "Inch"
}

class ViewModel {
    var settingsModel: SettingsModelProtocol?
    var unit: String {
        settingsModel?.unit ?? "--"
    }
}

var globalSettingsModel: SettingsModelProtocol = MetricSettingsModel()

var viewModel = ViewModel()
print(viewModel.unit)
viewModel.settingsModel = globalSettingsModel
print(viewModel.unit)
globalSettingsModel = ImperialSettingsModel()
print(viewModel.unit)
viewModel.settingsModel = globalSettingsModel
print(viewModel.unit)

Output:

  1. --
  2. cm
  3. cm
  4. Inch

Solution

  • Put another layer between the viewModel and the settingsModel. Like a settingsService, where every viewModel would have reference to the same service, and when you want to change the setting model, you do it in settingsService, which provides the settings model to the viewModel.

    settingsService.settingsModel = globalSettingsModel

    class ViewModel {
        var settingsService: SettingsServiceProtocol?
        var unit: String {
            settingsService?.settingsModel.unit ?? "--"
        }
    }