Singleton and init with parameter

前端 未结 6 1343
孤街浪徒
孤街浪徒 2020-12-24 07:02

I want to use the singleton pattern in my class which has a private init with parameter. It also has a class function called setup which configures

6条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-24 07:43

    I have a slightly different solution. This relies on

    1. Static variable is lazily initialised
    2. Using a Config struct to store the initialisation params
    3. Enforcing the setup call with a fatalError in init (if the setup call isn't called before accessing the singleton)

    .

    class MySingleton {
    
        static let shared = MySingleton()
    
        struct Config {
            var param:String
        }
        private static var config:Config?
    
        class func setup(_ config:Config){
            MySingleton.config = config
        }
    
        private init() {
            guard let config = MySingleton.config else {
                fatalError("Error - you must call setup before accessing MySingleton.shared")
            }
    
            //Regular initialisation using config
        }
    }
    

    To use this, you set it up with

    MySingleton.setup(MySingleton.Config(param: "Some Param"))
    

    (Obviously you can use multiple params if needed by expanding the MySingleton.Config struct)

    Then to access the singleton, you use

    MySingleton.shared
    

    I'm not wild about having to use a separate setup struct, but I like that this stays close to the recommended singleton pattern. Keeping the setup struct inside the singleton keeps things fairly clean.

    Note - the shared object is a singleton. In the background, swift uses dispatchOnce to guarantee that. However there is nothing stopping you from calling setup multiple times with different configs from different threads.

    At the moment, the first call to shared will 'lock' the setup.

    If you want to lock things down after the first call to setup, then just call

    _ = MySingleton.shared
    

    in setup

    Simple Example:

    class ServerSingleton {
        static let shared = ServerSingleton()
    
        struct Config {
            var host:String
        }
        private static var config:Config?
    
        let host:String
    
        class func setup(_ config:Config){
            ServerSingleton.config = config
        }
    
        private init() {
            guard let config = ServerSingleton.config else {
                fatalError("Error - you must call setup before accessing MySingleton.shared")
            }
    
            host = config.host
        }
    
        func helpAddress() -> String {
            return host+"/help.html"
        }
    }
    
    ServerSingleton.setup(ServerSingleton.Config(host: "http://hobbyistsoftware.com") )
    let helpAddress = ServerSingleton.shared.helpAddress()
    //helpAddress is now http://hobbyistsoftware.com/help.html
    

提交回复
热议问题