Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reset singleton instance?

Tags:

ios

swift

I'm creating a singleton instance like this

static let currentUser = User()

private override init() {
    super.init()
    // custom initialisation
}

How can I reset this instance or set back to nil?

like image 426
gpichler Avatar asked Dec 02 '15 15:12

gpichler


3 Answers

I create all my Singletons with an optional Singleton instance. However I also make this private and use a function to fetch it. If the Singleton is nil it creates a new instance.

This is actually the only good way to set up a Singleton. If you have a regular object that you can't deinitialize it's a memory problem. Singletons are no different, except that you have to write a function to do it.

Singletons have to be completely self managed. This means from init to deinit.

I have a couple of templates on github for Singeltons, one of them with a fully implemented read/write lock.

class Singleton {

    private static var privateShared : Singleton?

    class func shared() -> Singleton { // change class to final to prevent override
        guard let uwShared = privateShared else {
            privateShared = Singleton()
            return privateShared!
        }
        return uwShared
    }

    class func destroy() {
        privateShared = nil
    }

    private init() {
        print("init singleton")
    }

    deinit {
        print("deinit singleton")
    }
}
like image 91
R Menke Avatar answered Sep 19 '22 08:09

R Menke


You can not do that if you declare currentUser as let. It should be var instead, or better still private (set) var. Also you can not assign currentUser with nil if its type is User (inferred from the way you assign it at the moment). Instead, it should be User?.

For example, something like this:

/// ...

static private (set) var currentUser: User? = User()

static func resetCurrentUser() {
    currentUser = nil
}

// ...

private (set) allows changes to the property only within the scope of current file, and for the rest of your code it will be seen as let. Then method resetCurrentUser() can be used to put it to nil.


Or even this:

// ...

private static var _currentUser: User?

static var currentUser: User {
    if _currentUser == nil { _currentUser = User() }
    return _currentUser!
}

static func resetCurrentUser() {
    _currentUser = nil
}

// ...

You can have currentUser as computed property that guarantees to return a value. So you can reset the user to nil, yes. But if later you will try to read from there again a new instance will be created automatically.

Be careful with multithreaded access, though.

like image 41
0x416e746f6e Avatar answered Sep 19 '22 08:09

0x416e746f6e


All you want is possible, but highly unrecommended :) Because singletons by design should not fall back to nil.

First, if you want to change currentUser, it must be var. Then if you want it to be nil, it must by optional type and you should unwrap it when using.

static var currentUser: User? = User()

I would propose to not change currentUser or make it non-static (for example, a property of some UsersManager.

Also you can change properties of currentUser (like name, loggedIn). At last, take a look at this answer: https://stackoverflow.com/a/28398974/326017 - it describes your situation.

like image 34
brigadir Avatar answered Sep 18 '22 08:09

brigadir