Having a singleton use the value from initWithCoder instead of creating a new instance in Swift - singleton

I have a simple boolean variable in a function on which a set an observer to check when it changes:
var userValid: Bool{
didSet{
let valid=userValid ? "valid" : "not valid"
print("uservalid changed to \(valid)")
}
}
I set it to false in the init and then to true in the program: the initialiser is called twice once for the class and once for the subclass but I am alway checking the value in the class. So I am seeing the variable is set to true in the observer, but then when I check it in another function I find it at false without the observer to be ever called again.
As it comes out the problem seems to stem from the fact I initialise two times the class: once as a singleton and the other one with:
init?(coder aDecoder: NSCoder)
Of course I initialise the singleton with:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static let instance : MapDelegate = MapDelegate()
}
return Static.instance
}
How may I return the value generated from the initWithCoder instead of creating a new one?

I think I have fixed it by changing the singleton to:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static var instance : MapDelegate {
if let me = Factory.sharedFactory().mapHandler {
return me
} else {
Factory.sharedFactory().mapHandler=MapDelegate()
return Factory.sharedFactory().mapHandler
}
}
}
return Static.instance
}

Related

Object constructor and Delegates.notNull

object WalletConfig {
init {
fill(HashMap<String, String>())
}
var clientUrl: String by Delegates.notNull()
private set
fun fill(settingMap: Map<String, String>) {
try {
clientUrl = settingMap["URL_CLIENT"] ?: ""
} catch(ex:Exception) { }
}
}
throw ex: fill: Load 'wallet.config' config file: java.lang.NullPointerException at ru.WalletConfig.setClientUrl(WalletConfig.kt)
The problem is caused by the miss ordered init block and property initializer. As stated in the answer about class initialization semantics. The init block is not the constructor - its code is included in the primary constructor.
The following example:
class OrderOfInits {
constructor() {
println("constructor")
}
init {
println("A")
}
init {
println("B")
}
init {
println("C")
}
}
val a = OrderOfInits()
Would print:
A
B
C
constructor
Property delegates initialization is also part of primary constructor. Their initialization order in constructor reflects the order they were declared in. In other words the init { fill(...) } initializer block invokes clientUrl setter which in turn tries to call Delegates.notNull() instance method. However the instance field holding the Delegates.notNull() was not yet set hence NPE.
To fix the problem you just need to reorder them like so:
object WalletConfig {
var clientUrl: String by Delegates.notNull()
private set
init {
fill(HashMap<String, String>())
}
...
}

Swift 3 - Singleton

class MyManager {
private static var __once: () = {
Static.instance = MyManager()
}()
class var sharedInstance: MyManager {
struct Static {
static var onceToken: Int = 0
static var instance: MyManager? = nil
}
_ = MyManager.__once
return Static.instance!
}
fileprivate init() {
print("MyManager init");
}
....... etc
calling it
aManager = MyManager.sharedInstance
results in
MyManager init fatal error: unexpectedly found nil while unwrapping an Optional value
_ = MyManager.__once isn't calling your __once function, it's assigning it to nothing. You forgot the ():
MyManager.__once()
That's the whole purpose of requiring _ =, to make you realize you're dealing with the function itself, not a function call.
Regardless, this is an unnecessarily convoluted and messy implmentation of a singleton. All you need is:
class MyManager {
static let instance = MyManager()
}
It's lazy, thread-safe, and sane.
For me this is the best way, make init private.
// MARK: - Singleton
final class Singleton {
// Can't init is singleton
private init() { }
// MARK: Shared Instance
static let shared = Singleton()
// MARK: Local Variable
var emptyStringArray : [String] = []
}

Singleton with properties in Swift 3

In Apple's Using Swift with Cocoa and Objective-C document (updated for Swift 3) they give the following example of the Singleton pattern:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
Let's imagine that this singleton needs to manage a variable array of Strings. How/where would I declare that property and ensure it gets initialized properly to an empty [String] array?
For me this is the best way, make init private. Swift 3 \ 4 \ 5 syntax
// MARK: - Singleton
final class Singleton {
// Can't init is singleton
private init() { }
// MARK: Shared Instance
static let shared = Singleton()
// MARK: Local Variable
var emptyStringArray = [String]()
}
You can initialize an empty array like this.
class Singleton {
//MARK: Shared Instance
static let sharedInstance : Singleton = {
let instance = Singleton(array: [])
return instance
}()
//MARK: Local Variable
var emptyStringArray : [String]
//MARK: Init
init( array : [String]) {
emptyStringArray = array
}
}
Or if you prefer a different approach, this one will do fine.
class Singleton {
//MARK: Shared Instance
static let sharedInstance : Singleton = {
let instance = Singleton()
return instance
}()
//MARK: Local Variable
var emptyStringArray : [String]? = nil
//MARK: Init
convenience init() {
self.init(array : [])
}
//MARK: Init Array
init( array : [String]) {
emptyStringArray = array
}
}
As per the apple's documentation: In Swift, you can simply use a static type property, which is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously.
class Singleton {
// MARK: - Shared
static let shared = Singleton()
}
With initialization method:
class Singleton {
// MARK: - Shared
static let shared = Singleton()
// MARK: - Initializer
private init() {
}
}
Any initialisation would be done in an init method. No difference here between a singleton and a non-singleton.

Implementing a generic weak storage box which knows when the value becomes nil

Not long after I posted this question, I got an idea of how a generic weak storage box could be implemented, that knows and sends an event when the weak value it holds is deallocked.
Here's what I mean by that (an example implementation that doesn't work):
class WeakValue<T: AnyObject> {
weak var value: T? {
didSet { /* Send event here when value is changed __or becomes nil__ */ }
}
}
This doesn't work. For some reason, property observers are not triggered when they observe a weak var and it becomes nil (missing feature, anyone?).
So, here's the idea I had:
private class Watcher {
weak var delegate: WeakValue<AnyObject>?
init(delegate d: WeakValue<AnyObject>) { delegate = d }
deinit { delegate?.watcherWillDisappear() }
}
public class WeakValue<T: AnyObject> {
private let storage = NSMapTable.strongToWeakObjectsMapTable()
public init() {}
public init(value v: T?) { value = v; reloadValue() }
public weak var value: T? { didSet { reloadValue() } }
private func reloadValue() {
storage.removeAllObjects()
if let v = value { storage.setObject(v, forKey: Watcher(delegate: unsafeBitCast(self, WeakValue<AnyObject>.self))) }
}
private func watcherWillDisappear() {
/* Event triggered here */
}
}
The idea was to use the functionality of NSMapTable to my advantage. Here's how it should work:
When a value is set, a strong-key/weak-value pair is added to NSMapTable. The key is a Watcher class that only NSMapTable holds a reference to (that's why it has to be strong). The value is the actual value that is to be stored.
Whenever the value is deallocked, NSMapTable removes the key/value pair from its storage, which in turn deallocks the Watcher class (set as the key and which only NSMapTable holds a reference to), which, when doing so, warns the WeakValue class.
My question is twofold:
This doesn't seem to work (I didn't test this on a Playground, I tested it on a real project): the test class I feed to WeakValue is deallocked, but watcherWillDisappear is not called. Why doesn't it work?
This is not very efficient, right? (creating a new NSMapTable for every weak value I want to store and for which I need an alert when deallocked)

Swift property override not working

When I try to override a property I get an error "can not override mutable property with read-only property"
I have provided get and set in the super class.
class Card {
var contents:String {
get {
return self.contents
}
set {
self.contents = newValue
}
}
init() {
self.contents = ""
}
}
Here is my Subclass where I am trying to override the "contents" property.
class PlayingCard: Card {
override var contents:String { //<-- this is where I get the build error
get {
var rankStrings:Array<String> = PlayingCard.rankStrings()
return rankStrings[Int(self.rank)] + self.suit
}
}
}
What exactly am I doing wrong?
If the property you're overriding has both a getter and a setter, you need to provide both in your subclass as well. Here's the relevant part from the Swift language guide (emphasis mine):
You can present an inherited read-only property as a read-write
property by providing both a getter and a setter in your subclass
property override. You cannot, however, present an inherited
read-write property as a read-only property.
If you're not doing anything special with the value, then you'll typically want to pass the value being set on to the base class:
set {
super.contents = newValue
}
You could also just discard the value with an empty setter (although I can't think of a good reason to do this offhand):
set { }
I also wanted to point out that you have an infinite loop in the contents property in your Card class. When you you do this:
get {
return self.contents
}
You're actually just calling that same getter again, creating an infinite loop; you're doing the same with the setter. Swift doesn't create ivars for your properties automatically like Objective-C did, so you need to create them yourself. A more appropriate way to create that property would be to do something like this:
class Card {
private var _contents: String
var contents: String {
get {
return _contents
}
set {
_contents = newValue
}
}
init() {
_contents = ""
}
}
However, since you're not doing anything other than setting and returning _contents in your setter and getter, you can simplify it down to this:
class Card {
var contents: String = ""
init() {
}
}
Note: contents might also be a good candidate for using an optional (String?) and setting it to nil rather than initializing it to an empty string.
The compiler error message is fairly straightforward: Card's contents property is mutable, which is to say it has a set method in addition to the get method.
Your override only adds a get method, you need to add a set method too.
I think this is what you want:
set(newValue) {
rankStrings[Int(self.rank)] = newValue;
}