I have a singleton class:
class SomeManager {
static let sharedInstance = SomeManager()
let serverService = SomerServerService()
let musicService = SomeMusicService()
}
I try to use
class SomeMusicService
{
let serverService = SomeManager.sharedInstance.serverService //here seems I get cycle.
}
Should I use lazy or some other initialization.
As you can see let musicService = SomeMusicService() initializes an object and then in the same object SomeMusicService it tries to call sharedInstance of SomeManager singleton to get another service at start.
So this is a full listing:
import Foundation
class ServerService
{
func downloadMusic()
{
print("Download music and play it after that.")
}
}
class MusicService
{
let serverService = Singleton.shared.serverService
func playMusic()
{
serverService.downloadMusic()
}
}
class Singleton
{
static let shared = Singleton()
let serverService = ServerService()
let musicService = MusicService()
}
let s = Singleton.shared
print("Hello, World!")
We never get print("Hello, World!") line to be invoked.
You could use weak to avoid the retain cycle, but the better answer is a computed property:
class SomeMusicService {
var serverService: SomeService { return SomeManager.sharedInstance.serverService }
}
I see from your updated code what the cycle is. Here's how it plays out:
Call Singleton.shared
Begin to construct Singleton
Construct ServerService (for serverService property)
Begin to construct MusicService (for musicService property)
Call Singleton.shared (for serverService property)
Block waiting for Singleton.shared to complete
The program is now deadlocked waiting on itself.
The right answer is to use a computed property so that there is no need to call Singleton.shared during construction. A lazy property would work as well, but seems a lot of trouble for this (and risks creating retain loops between the services).
Related
In this post, it is very nicely explained how Singletons should be implemented in Swift, essentially it can be done with two lines:
class TheOneAndOnlyKraken {
static let sharedInstance = TheOneAndOnlyKraken()
private init() {} //This prevents others from using the default '()' initializer for this class.
}
However, what happens if my Singleton is supposed to be initalised with some data? Maybe it needs to encapsulate an API Key or other data that it can only receive from the outside. An example could look as follows:
class TheOneAndOnlyKraken {
let secretKey: String
static let sharedInstance = TheOneAndOnlyKraken()
private init() {} //This prevents others from using the default '()' initializer for this class.
}
In that situation, we can't make the initializer private because we will have to create an initializer that takes a String as an argument to satisfy the compiler:
init(secretKey: String) {
self.secretKey = secretKey
}
How can that be saved and we still make sure that we have a thread-safe instantiation of the singleton? Is there a way how we can avoid using dispatch_once or would we have to essentially default back to the Objective-C way where we use dispatch_once to make sure that the initializer indeed only gets called once?
First, note that the ObjC way you're implying is not thread-correct. It may be "safe" in that it doesn't crash and does not generate undefined behavior, but it silently ignores subsequent initializations with differing configuration. That is not expected behavior. Readers that are known to occur after the write will not receive the written data. That fails consistency. So put aside theories that such a pattern was correct.
So what would be correct? Correct would be something like this:
import Dispatch
class TheOneAndOnlyKraken {
static let sharedInstanceQueue: DispatchQueue = {
let queue = DispatchQueue(label: "kraken")
queue.suspend()
return queue
}()
private static var _sharedInstance: TheOneAndOnlyKraken! = nil
static var sharedInstance: TheOneAndOnlyKraken {
var result: TheOneAndOnlyKraken!
sharedInstanceQueue.sync {
result = _sharedInstance
}
return result
}
// until this is called, all readers will block
static func initialize(withSecret secretKey: String) {
// It is a programming error to call this twice. If you want to be able to change
// it, you'll need another queue at least.
precondition(_sharedInstance == nil)
_sharedInstance = TheOneAndOnlyKraken(secretKey: secretKey)
sharedInstanceQueue.resume()
}
private var secretKey: String
private init(secretKey: String) {
self.secretKey = secretKey
}
}
This requires a single explicit call to TheOneAndOnlyKraken.intialize(withSecret:). Until someone makes that call, all requests for sharedInstance will block. A second call to initialize will crash.
I've defined a global struct with static properties with values I use in many of my view controllers, like this:
public struct AppGlobal {
static var currentUser = UserModel()
static let someManager = SomeManager()
// Prevent others from initializing
private init() { }
}
Then in my UIViewController, I can do something like this:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AppGlobal.currentUser.prop1 = "abc123"
AppGlobal.someManager.startUpdating()
}
}
This is obviously very convenient, but smells really bad. I believe dependency injection would come in handy here, but not sure how. Is there a more elegant alternative to creating the AppGlobal singleton properties?
I can't see why you need to access userModel or someManager through a global state (and yes — Singletons are just that).
Why not just set it where you need it?
"Dependency Injection" is a 25-dollar term for a 5-cent concept.
That's not to say that it's a bad term…
[…]
Dependency injection means
giving an object its instance variables. Really. That's it.
– James Shore: Dependency Injection Demystified
Either do it during constructing
class C {
let currentUser: UserModel
let someManager: SomeManager
init(currentUser:UserModel, someManger:SomeManager) {
self.currentUser = currentUser
self.someManager = someManager
}
}
or through properties. If you need to make sure that all properties are set, do something like this:
class MyController: UIViewController {
var currentUser: UserModel? {
didSet{
self.configureIfPossible()
}
}
var someManager: SomeManager?{
didSet{
self.configureIfPossible()
}
}
func configureIfPossible(){
if let currentUser = self.currentUser, someManager = self.someManager {
// configure
}
}
}
In my current project we have the policy that every dependency must be visible and configurable from outside the class.
An example:
class LibrarySegmentViewController: BaseContentViewController {
var userDefaults: NSUserDefaults?
var previousSorting : LibrarySortingOrder = .AZ
var sorting : LibrarySortingOrder {
set{
self.previousSorting = sorting
if let filterMode = self.filterMode {
self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting")
}
self.setupIfReady()
}
get{
if let filterMode = self.filterMode {
if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) {
return s
}
}
return .Date
}
}
}
So as you can see, we even use properties to reference NSUserDefaults.standardUserDefaults(). We do this as we can pass in fresh instances during testing, without bigger mocking hassle.
And this is the most importing reason why not to use singletons directly: The dependencies are hidden and might bite you during testing and refactoring. Another example would be an API client singleton that is hidden in the code and performs unwanted networking requests during testing. If it is set from outside of the tested class you can just pass in a mocked networking client that does not perform any requests but returns test data.
So even if you use singletons, you should pass it in as a dependencies.
If this question is about global or not, you should see this thread :
What is so bad about singletons?
But if you want a better design for your implementation of a singleton you can try something like this :
class SingletonExample: NSObject {
static let sharedInstance: SingletonExample()
}
class OtherSingletonExample: NSObject {
static let sharedInstance: OtherSingletonExample()
}
Then you can use SingletonExample.sharedInstance and OtherSingletonExample.sharedInstance anywhere in your code.
The idea is to isolate one singleton from another and access it as a class attribute instead of creating a big global struct for anything.
I have written a helper struct for saving and loading stuff to NSUserDefaults.
import UIKit
struct Database {
static let defaults = NSUserDefaults.standardUserDefaults()
static var myVariable: AnyObject?
static func save() {
defaults.setObject(myVariable, forKey: "myVariable")
}
static func load() {
if let myVariable = defaults.objectForKey("myVariable") {
self.myVariable = myVariable
}
}
static func clear() {
defaults.removeObjectForKey("myVariable")
}
}
Now I can simply use Database.load() to load myVariable from NSUSerDefaults.
However, the same is achievable with this code:
struct Database2 {
static var sharedInstance = Database()
let defaults = NSUserDefaults.standardUserDefaults()
var myVariable: AnyObject?
func save() {
defaults.setObject(myVariable, forKey: "myVariable")
}
func load() {
if let myVariable = defaults.objectForKey("myVariable") {
self.myVariable = myVariable
}
}
func clear() {
defaults.removeObjectForKey("myVariable")
}
}
Now I would use Database2.sharedInstance.load().
Which one is seen as a better practice and why? What's the use of a sharedInstance, if I can do everything I want with the static declaration?
A shared instance is recommendable, at least for the following reasons:
class methods make unit testing harder
you need class instances for dependency injection
if later on you decide that a non-singleton is more suitable - e.g. you decide to have two persistence storages for "myVariable", then you're stuck
and not lastly, class members live in the global space, and we should avoid using globals
The real question you should ask, is if you really need a singleton (with or without a shared instance) for your problem. If the only reason to have a singleton is ease-of-access, then you don't really need a singleton.
P.S. There is a very good article on objc.io about singletons, and although it was written for Objective-C, many concepts from there apply in Swift too.
// with singleton pattern, there exist only one copy of the object
// sigleton pattern can be applied for reference type only
// let st1 = Singleton(); let st2 = Sigleton(); st1 === st2
// in your example, S is value type. All instances of S share only type properties, here only i
struct S {
static var i: Int = 100
var j: Int
func foo() {
//print(i) // error: static member 'i' cannot be used on instance of type 'S'
print(S.i)
}
init(_ j: Int) {
self.j = j
}
}
var s1 = S(1)
var s2 = S(2)
//s1.i // error: static member 'i' cannot be used on instance of type 'S'
S.i // 100
s1.foo() // 100
s1.j // 1
s2.foo() // 100
s2.j // 2
S.i = 200
s1.foo() // 200
s2.foo() // 200
by the way, this (your) approach can be very useful and could be preferred in some situations.
Please help me with Swift,
I need singleton with can inheritance.
I can do like this
class A {
var defaultPort: Int
required init() {
self.defaultPort = 404
}
class var defaultClient: A {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return Static.instance!
}
}
but in swift 2.0 we can do like this
static let defaultClient = A() //self.init()
but it creates an instance of the class A any way.
How i can use like this self.init()
static let defaultClient = self.init()
in order to be able to inherit
UPD
best way for now
class A {
class func defaultClient() -> Self {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return instance(Static.instance, asType: self)
}
}
here we need helper as
func instance<T>(instance: Any, asType type: T.Type) -> T {
let reurnValue = instance as! T
return reurnValue
}
because another way cast A to Self not exist, for now.
p.s. crazy swift way!
why i can not do instance as! Self
Your question isn't very clear. You're looking for something like the class constant solution posted in this answer, but which automatically uses "my own class" instead of explicitly creating an instance of a specific class... right?
That is, you want to turn this:
class Singleton {
static let sharedInstance = Singleton()
}
into this:
class Singleton {
static let sharedInstance = SomeMagicThing()
}
class SingletonSubclass {}
where SomeMagicThing automatically creates a Singleton instance when you call Singleton.sharedInstance, and a SingletonSubclass instance when you call SingletonSubclass.sharedInstance. Correct?
Sorry, that can't be done (as of Swift 2.1).
Part of your issue is that static and class mean two different things. The static modifier means that the declaration it modifies is associated only with a specific type declaration. So, the Singleton type owns a pointer to a specific object -- its subclasses don't inherit that pointer. (And if they did, would it point to the same object or a subclass-specific one?)
If you could create a class var or class let, that'd (in theory) give you the kind of dispatch/inheritance you want. But trying that gives you an error (emphasis mine):
class stored properties not yet supported in classes; did you mean static?
So it sounds like this sort of thing might show up someday.
Of course, the other side of the problem is finding a way to dynamically refer to the "current" type responsible for executing some statement. In the context of an instance method, you have self.dynamicType for such things... but there's no equivalent for classes. (Self is a type constraint, not an actual type.) This is a side effect of the type system in Swift being much more strict and static than that of Objective-C (for example, metatypes aren't just a special flavor of otherwise normal objects). File a bug if you'd like to see a change to that effect?
I'm writing a singleton class to access socket by adopting socket.IO-objc, here's what I did so far:
class Singleton_SocketManager: NSObject, SocketIODelegate {
var isSocketConnected: Bool = false
var socket: SocketIO
override init() {
super.init()
}
class var sharedInstance: Singleton_SocketManager {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: Singleton_SocketManager? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = Singleton_SocketManager()
}
return Static.instance!
}
}
Yet the compiler complains:
Property 'self.socket' not initialized at super.init call
How should I write my init method here to make the compilation error go away?
By the way, I transitioned the code above from objective-c, in obj-c, the SocketIO is initialized like so:
self.socket = [[SocketIO alloc] initWithDelegate:self];
And If I put the init method this way:
override init() {
self.socket = SocketIO(delegate: self)
super.init()
}
It complains:
self used before super.init call
Is it necessary to inherit from NSObject for your application? I ran into a similar situation where I needed to set the Singleton as a delegate (so I needed self). By not inheriting from NSObject, my issue was resolved - no need to call super.init() anyway then
Apple's recommendation for a Singleton is like this :
If you need to perform additional setup beyond initialization, you can assign the result of the invocation of a closure to the global constant:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
But a (I think) more recent syntax can also be found on their swift blog, which I prefer :
class Singleton {
static let sharedInstance = Singleton()
private init() {
// do your init here
print("Singleton created")
}
}
You can follow the below option as suggested in the below url
Error in Swift class: Property not initialized at super.init call - How to initialize properties which need use of self in their initializer parameter
var socket: SocketIO!
Quote from The Swift Programming Language, which answers your question:
“Swift’s compiler performs four helpful safety-checks to make sure
that two-phase initialization is completed without error:”
Safety check 1 “A designated initializer must ensure that all of the
“properties introduced by its class are initialized before it
delegates up to a superclass initializer.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
Credits: Ruben on this question
Another solution is to make the 'socket' variable unwrapped optional.
var socket:IOSocket!