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

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)

Related

How to skip defined getters or setters in Kotlin

In java you can do the follwing:
public class Foo {
private String bar = "text";
public void method() {
// direct access (no logic)
System.out.println(this.bar);
}
// only if you access the object from the outside
// you are forced to use the getter with some logic in it
public String getBar() {
System.out.println(this.bar);
return this.bar;
}
}
But if you define a getter or a setter with logic in Kotlin you are forced to always execute this logic when accessing the field:
class Foo {
var bar: String = "text"
get() {
println(field)
return field
}
private set
fun method() {
// this also executes the getter
// Is it possible to skip the getter
// and directly access the field?
println(this.bar)
}
}
Is there a better way to access the field without executing the getter or setter logic than creating your own fun getBar() in Kotlin?
There is no possible way to skip a getter or a setter, they are intended to block the direct access of a property.
What you can do is make a multi-reference to same value (fake-referencing):
private var _bar: String = "text"
var bar
get() {
// some operations intercepting the getter
return _bar
}
// direct access
_bar
// intercepted access public field
bar
In Kotlin the backing fields (in your case the private variable) are not exposed by design. There are a few exceptions explained here: https://kotlinlang.org/docs/reference/properties.html#backing-fields
All access to val and var happens through implicit getters and setters. A val resolves to a property with a getter() while var resolves to a property with a getter and a setter: https://kotlinlang.org/docs/reference/properties.html#properties-and-fields

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

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
}

KVO or how to listen for a property changes from outside in Swift

I have a instance with a property which I want to listen for updates from other instance.
For example class Menu has a property badgeCount, I want to listen for any updates for badgeCount for example when badgeCount is changed. I want my ViewController to have callback after badgeCount is modified to know actual data.
In objective was KVO that I can use for listed property, how can I use KVO in Swift. I am new in Swift.
If you want to use KVO in swift, there are two requirements :
The class you want to do KVO on must inherit from NSObject (or any NSObject subclass)
The property you need to observe must be marked as dynamic
a code example would be:
class Menu: NSObject {
dynamic var badgeCount: Int = 0
}
And then, you can use the usual menuInstance.addObserver(self, forKeyPath: "badgeCount", options: NSKeyValueObservingOptions(), context: nil)
But this solution is not very much swifty.
Better solutions are (not an exhaustive list):
Use swift's didSet/willSet to call some callback
class Menu {
var badgeCount: Int = 0 {
didSet {
badgeCountChangedListener(badgeCount)
}
}
init(badgeCountChangedListener: (Int -> Void)) {
self.badgeCountChangedListener = badgeCountChangedListener
}
private let badgeCountChangedListener: (Int -> Void)
}
Use RxSwift's Variable type
class Menu {
let badgeCount = Variable(0)
}
// and from where you observe
menuInstance.badgeCount.subscribeNext { badgeCount in
print(badgeCount)
}

Computed property of closures

I would like to use a closure as a computed property. I mean something like the code below.
class MyClass {
typealias myFuncType = () -> (Void)
private var _myAction:myFuncType
var myAction:myFuncType = {
set(newAction){
self._myAction = newAction
}
}
}
Is it possible or will the compiler think that as I opened a bracked it must be the closure definition?
Closures (and functions) are advertised as first class citizens in swift, so you can store them in variables and properties like any other data type.
That said, your code is almost good, you just have to remove the '=' because otherwise it's considered as a stored property with inline initialization. The correct code is:
var myAction:myFuncType {
set(newAction) {
self._myAction = newAction
}
get { // see notes below
return _myAction
}
}
Some notes:
there's no need to use a computed property backed by a stored property - your code is equivalent to:
class MyClass {
typealias myFuncType = () -> (Void)
var myAction: myFuncType
}
if you need to make additional processing when setting the property, make use of Property Observers: willSet and didSet
in a computed property, if you implement a setter, you must also provide a getter

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;
}