25

How to destroy a singleton in Swift?

I create a singleton like this:

class MyManager  {
    private static let sharedInstance = MyManager()
    class var sharedManager : MyManager {
        return sharedInstance
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Dennis
  • 455
  • 2
  • 7
  • 14
  • What do you mean by "destroy"? Memory is automatically taken care of by ARC (Automatic Reference Counting). You don't need to keep track of the memory used by variables and you don't need to manually release the memory they use. – Arc676 Nov 04 '15 at 15:09
  • 3
    @Arc676, not really. This is a static method, ARC will never kill it. You need to force it to rebuild. – brduca Nov 04 '15 at 15:59
  • 1
    if you need to explicitly destroy the instance and assign a new one, then just change the `let` to `var` and implement a method that assign another MyManager() to it, and the previous instance will be collected by ARC – cezheng Nov 04 '15 at 16:06
  • change the `let` to `var`, will it be thread safe? – Dennis Nov 05 '15 at 07:31

3 Answers3

39

Just a simple example on how to dispose the current instance of a Singleton:

import UIKit

class AnyTestClass
{
    struct Static
    {
        private static var instance: AnyTestClass?
    }

    class var sharedInstance: AnyTestClass
    {
        if Static.instance == nil
        {
            Static.instance = AnyTestClass()
        }

        return Static.instance!
    }

    func dispose()
    {
        AnyTestClass.Static.instance = nil
        print("Disposed Singleton instance")
    }

    func saySomething()
    {
        print("Hi")
    }

}

// basic usage
AnyTestClass.sharedInstance.saySomething()
AnyTestClass.sharedInstance.dispose()

Hope it might help.

brduca
  • 3,573
  • 2
  • 22
  • 30
12

If you want to be able to destroy it, make it an optional. And don't use ! to force unwrap like in brduca answer: it wouldn't be thread safe. This answer is safer:

class MyManager  {
    private static var sharedInstance: MyManager?
    class var sharedManager : MyManager {
        guard let sharedInstance = self.sharedInstance else {
            let sharedInstance = MyManager()
            self.sharedInstance = sharedInstance
            return sharedInstance
        }
        return sharedInstance
    }
    class func destroySharedManager() {
        sharedInstance = nil
    }
}

Basic usage:

// do something with singleton
AnyTestClass.sharedManager.doSomething()
// destroy singleton
AnyTestClass.destroySharedManager()
// do something with new singleton
AnyTestClass.sharedManager.doSomething()
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Having "destroySharedManager" as a class func makes it safer but no thread safe as you claim. Since it's not locking the access of "sharedInstance", so when returning it it's not sure that it exists. – brduca Oct 23 '18 at 13:32
  • Imagine that instance exists, inside sharedManager your guard let will not be performed and you will return the sharedInstance (thats a pointer for a nullable var, that was copied), at the same time it's disposed in another thread. – brduca Oct 23 '18 at 13:37
  • You will need dispatch queue for that, here is a example: https://stackoverflow.com/questions/27822117/thread-safe-access-to-a-variable-in-a-class – brduca Oct 23 '18 at 13:45
  • @brduca you seem to misunderstand how Swift works: `let` is a strong reference within its scope, so my implementation will never return nil and never crash. There is no need for dispatch here. – Cœur Oct 23 '18 at 16:01
  • So explain to me what happens if (at the same time, in different threads) one disposes and the other holds a strong pointer. – brduca Oct 23 '18 at 16:06
  • @brduca you need to clarify what you mean by your example situation, but if one holds a strong pointer somewhere, if then sharedInstance gets nullified, and if then sharedManager gets called, you'll simply end up with two instances (the old one that you are holding and the new one created because MyManager.sharedInstance was nil). Multiple instances is inevitable with destroyable singletons, but what the pattern garanties is to always return the same instance if no disposal is requested. – Cœur Oct 23 '18 at 16:20
  • @brduca maybe what confuses you is the naming in `let sharedInstance = self.sharedInstance`, as I'm declaring a local variable with an identical name as the outer scope variable? If that's the case, feel free to read my code as: `guard let strongInstance = self.sharedInstance else { let strongInstance = MyManager(); self.sharedInstance = strongInstance; return strongInstance } return strongInstance` – Cœur Oct 23 '18 at 16:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182372/discussion-between-brduca-and-coeur). – brduca Oct 23 '18 at 16:22
7

You don't destroy a singleton. A singleton is created the first time anyone needs it, and is never destroyed as long as the application lives.

gnasher729
  • 51,477
  • 5
  • 75
  • 98