Swift 4 approach for observeValue(forKeyPath:...) - swift

I've been trying to find an example, but what I've seen doesn't work in my case.
What would be the equivalent of the following code:
object.addObserver(self, forKeyPath: "keyPath", options: [.new], context: nil)
override public func observeValue(
forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
}
The code above works, but I get a warning from SwiftLink:
Prefer the new block based KVO API with keypaths when using Swift 3.2 or later.
I appreciate it if you can point me in the right direction.

Swift 4 introduced a family of concrete Key-Path types, a new Key-Path Expression to produce them and a new closure-based observe function available to classes that inherit NSObject.
Using this new set of features, your particular example can now be expressed much more succinctly:
self.observation = object.observe(\.keyPath) {
[unowned self] object, change in
self.someFunction()
}
Types Involved
observation:NSKeyValueObservation
change:NSKeyValueObservedChange
\.keyPath: An instance of a KeyPath class produced at compile time.
Key-Path grammar
The general grammar of a Key-Path Expression follows the form \Type.keyPath where Type is a concrete type name (incl. any generic parameters), and keyPath a chain of one or more properties, subscripts, or optional chaining/forced unwrapping postfixes. In addition, if the keyPath's Type can be inferred from context, it can be elided, resulting in a most pithy \.keyPath.
These are all valid Key-Path Expressions:
\SomeStruct.someValue
\.someClassProperty
\.someInstance.someInnerProperty
\[Int].[1]
\[String].first?.count
\[SomeHashable: [Int]].["aStringLiteral, literally"]!.count.bitWidth
Ownership
You're the owner of the NSKeyValueObservation instance the observe function returns, meaning, you don't have to addObserver nor removeObserver anymore; rather, you keep a strong reference to it for as long as you need your observation observing.
You're not required to invalidate() either: it'll deinit gracefully. So, you can let it live until the instance holding it dies, stop it manually by niling the reference, or even invoke invalidate() if you need to keep your instance alive for some smelly reason.
Caveats
As you may have noticed, observation still lurks inside the confines of Cocoa's KVO mechanism, therefore it's only available to Obj-C classes and Swift classes inheriting NSObject (every Swift-dev's favorite type) with the added requirement that any value you intend to observe, must be marked as #objc (every Swift-dev's favorite attribute) and declared dynamic.
That being said, the overall mechanism is a welcomed improvement, particularly because it manages to Swiftify observing imported NSObjects from modules we may happen to be required to use (eg. Foundation), and without risking weakening the expressive power we work so hard to obtain with every keystroke.
As a side-note, Key-Path String Expressions are still required to dynamically access NSObject's properties to KVC or call value(forKey(Path):)
Beyond KVO
There's much more to Key-Path Expressions than KVO. \Type.path expressions can be stored as KeyPath objects for later reuse. They come in writable, partial and type-erased flavors. They can augment the expressive power of getter/setter functions designed for composition, not to mention the role they play in allowing those with the strongest of stomachs to delve into the world of functional concepts like Lenses and Prisms. I suggest you check the links down below to learn more about the many development doors they can open.
Links:
Key-Path Expression # docs.swift.org
KVO docs # Apple
Swift Evolution Smart KeyPaths proposal
Ole Begemann's Whats-new-in-Swift-4 playground with Key-Path examples
WWDC 2017 Video: What's New in Foundation 4:35 for SKP and 19:40 for KVO.

To add something to the answer as I experienced crashes on my app when using this method in iOS 10.
In iOS 10, you still need to remove the observer before deallocating the class or otherwise you will get a crash NSInternalInconsistencyException stating that:
An instance A of Class C was deallocated while key value observers were still registered with it.
To avoid this crash. Simply set the observer property that you're using to nil.
deinit {
self.observation = nil
}

Related

Is it possible to use an alias for `self` in swift?

Swift appears to share with python one characteristic of requiring the class instance reference to access the members - even inside the class itself. The default in both languages is self. In particular
self.someClassMethod()
This is identical between python and swift. I also dislike this requirement finding it to be intrusive: it attracts my attention to self and away from which method is actually being invoked. In python I reduce (though do not remove) the annoyance by using s instead:
def someInstanceMethod(s, param1, param2)
instead of the standard
def someInstanceMethod(self, param1, param2)
Then inside the method I can access other instance methods :
s.someOtherInstanceMethod()
I'm not going to fight any battles on this: PEP folks will jump up and down about it -but it is more readable to me and others in my team. Is there any such way to do a shortcut in swift? I noticed typealias and tried to use it:
fileprivate let tp = U.tprint // Any non-critical logging statements will happen with this
But then it is necessary to do this:
self.tp("Loaded synthesizer settings")
Without the reference to self the following error occurs:
(162, 25) reference to property 'tp' in closure requires explicit 'self.' to make capture semantics explicit
I would prefer just
tp("Loaded synthesizer settings")
but that is not apparently possible. Can we get closer to that - along the lines of s.<method> instead of self.<method> ?
It's a little unclear what the question is, or what you think is the purpose of passing self around, so here's a quick summary of the key facts:
There are instance members and type members (type members are marked static or class).
If a method is an instance method, it does not need to say self to access instance members.
If a method is a type method, it does not need to say self to access type members.
If a method is an instance method, it can say Self to access type members.
If a method is a type method, there is no instance so instance members cannot be accessed.

Use self in singleton struct

I have a simple question about singleton in swift, after a lot of research I didn't find a clear answer for that. So question is - I have a StructA:
struct StructA {
static let shared = StructA()
private init() {}
public func someFuncA() {
//self.somefuncB()
//or
//StructA.shared.someFuncB()
}
private func someFuncB() {
}
}
I call someFuncA from other class like this StructA.shared.someFuncA():
Can you please explain me what the difference self.somefuncB() and StructA.shared.someFuncB() (see above code) ?
In my opinion there is no difference, but what if I have such code when self.somefuncB() must be called in callback -
So must I use [weak self]?
public func someFuncA() {
someFuncWithCallback() { [weak self] in
self?.somefuncB()
}
}
or can I just write
public func someFuncA() {
someFuncWithCallback() {
StructA.shared.someFuncB()
}
}
I checked this code with "Leaks" (Xcode instruments) it says that there is no leak, as I know closer/block owns objects that used in it, so can someone explain me what here happens ? thanks.
A couple of thoughts:
A struct singleton is a contradiction in terms. A singleton is an object where there should be only one instance. But struct is a value-type and has "copy" memory semantics. Consider:
var a = StructA.shared
...
The a is a copy of the so-called singleton, not a reference to it. To avoid this problem, the singleton should be a class, a reference type.
I agree with Paulw11, that self is a simpler and more common approach. I'd also suggest, though, that by referencing self, you can better write code that (a) is not dependent on the class being a singleton; and (b) opens the possibility of the class being subclassed at some future date.
Given that I would advise self pattern, I would therefore also suggest avoiding obvious potential strong reference cycles (e.g. by employing weak or unowned references where needed). There's no point in knowingly creating what could be strong reference cycle simply because it happens to be a singleton. Why write code that you know you'd have to rewrite if you ever revisited the decision to use singleton pattern, especially when you know how easy it is to avoid strong references in the first place?
FYI, I'm seeing the same behavior that you report, that if a static participates in a theoretical strong reference cycle, it's not identified as such. But if you set that static property to nil (assuming it was variable and optional), the strong reference appears.
This observation doesn't change my recommendation above, namely to avoid what you know would be a strong reference cycle in any other context. I'm merely confirming your empirical observation.
Regarding points 2 through 4 above (where I contemplate some potential eventual refactoring of singleton pattern into some other pattern), I should say that this is not a purely academic observation. It's not uncommon to have some singleton type, and later, as the project becomes more complicated or employs more unit tests, to revisit that decision and start employing dependency injection or other patterns. It would be a shame if you had to edit all of the individual functions as well. If you write the code to not depend upon the singleton nature of the object, you end up with more robust code base with fewer unnecessary internal dependencies.

How to observe key path on 'Any' object in Swift 4

I'm using the new Swift 4 KVO and KeyPath APIs to observe changes on an object. Specifically I'm trying to observe something on the selection object of an NSArrayController. The problem is the selection is of type Any and that seems to be at odds with generating the required keypath, since the compiler doesn't know of any properties on an object of type Any.
The property's name is assetPointHeight. And my code looks like this:
var observation: NSKeyValueObservation?
observation = arrayController.observe(
#keyPath(NSArrayController.selection.assetPointHeight),
options: [.new],
changeHandler: { [weak self] (_, _) in
self?.updateLabel()
}
)
I get two compile errors:
Generic parameter Value could not be inferred
Type 'Any' has no member 'assetPointHeight'
How can I achieve what I'm looking for here? Is there another way of generating this KeyPath?
I would not expect this to work because assetPointHeight isn’t a real property on selection (eg, it’s not defined anywhere in source code, it’s a virtual property created at runtime). I think what’s happening here is the Swift 4 version of observe(...) is trying to resolve that path to a static type and cannot, so it’s throwing an error. (Observing only works on NSObject subclasses, as well, so Any could never be observed.) So in this case you would have to use traditional string-based KVO, as “vadian” said.

In a Swift extension, get the actual calling object?

Say we are in an instance of SomeClass, consider this simple call
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(SomeClass.fixer(_:)),
name:"FixerNote",
object:nil)
Say we decide to make an extension to save typing, that will look like this ...
"FixerNote".does( #selector(SomeClass.fixer(_:)) )
Here's the extension...
public extension String
{
func does(s:Selector)
{
NSNotificationCenter.defaultCenter().addObserver
.. here, you need the actual SomeClass that called us .. ,
selector: s,
name:self,
object:nil)
}
}
How to know which object called the extension??
(NB, I realize you could pass it in or use it as the base :) )
Can you do such a thing in Swift? Can you find out who called you?
A similar issue: in the example, could you find out what object a selector ("s" in the example) belongs to ??
It's generally possible to iterate the stack trace of a program, but you need debug symbols to figure out where the self parameter of a method lives, and it might not even be anywhere anymore on an optimized build, or the caller might have been inlined, or have suffered some other destructive fate at the whim of the optimizer. So while it's possible to get an approximation of what method called you, it's not possible to get the self parameter of your caller on a deployed, symbol-less, optimized build.
And no, it's not possible to get a class out of a selector either. A selector is really just a string that identifies a method name, like "fixer:". The #selector() syntax only ensures that the compiler generates the correct selector name for a method (considering eventual #objc annotations) and helps refactoring tools understand what is happening.
I think the principle that the "owner object is in control of how or if it is exposed to child" is one of the most fundamental things in programming.
Having a mechanism that would easily allow the child to reflect the parent object would wreak unimaginable havoc to our codebases.

Closure identity in swift: unregister observing closure

When rethinking my everyday programming patterns to be more swifty, there is one, that I really struggle with: observing changes. After a lot of thinking and research I have yet to find a satisfying solution. That is one,
that is easy to use,
leverages the full potential of swift's strong type system,
is compatible with value types and
allows for static dispatch.
Maybe the latter one is not possible and that's the reason why my search is unsuccessful so far. If so, I would like to know why?
Some of the work-arounds I found so far:
SO: Observer Pattern in Swift (Using Any or objective_c runtime functionality)
Solving the binding problem with Swift (IMHO rather awkward to use)
The ones based on closures e.g Answer by Airspeed Velocity
The third one is so far the one that ticks the most boxes it's type safe, straight forward to use, and compatible with value types. For reference:
// central part is an observable protocol that can be fulfilled by
// any observable type.
protocol Observable {
associatedtype Value
func register(f: Value->())
}
// this would be implemented like
struct ObeservableInt: Observable {
// observable value
var value: Int {
didSet {
// inform all observers
for f in observers {
f(value)
}
}
}
var observers = Array<Int->()>()
mutating func register(f: Int->()) {
observers.append(f)
}
}
So far so good. But what happens if our observer is not needed any more? To avoid a memory leak we should unregister it. But this is seemingly not possible with this architecture. Despite being reference types, closures don't have a reliable identity. That is unless we force dynamic dispatch by annotation with #objc_block. Another alternative is to return a token from register(f:) and use that in an the unregister(token:) call.
So my question is, are there any better alternatives regarding the listed criteria? If not, which one of the two solutions #objc_block or using token is the preferred one?