Hello,
I encountered an issue on Xcode 9.4.1(9F2000) using Swift 4.1.
I'm implementing a custom Operation (NSOperation) and so I need to override different properties of the Operation class and notify through KVO when those values are changing (isExecuting
and isFinished
in my case) using willChangeValue(for: KeyPath)
and didChangeValue(for: KeyPath)
.
Code example:
class CustomOperation: Operation
private var internalExecutingState = false
private var internalFinishedState = false
override var isExecuting: Bool {
get {
return internalExecutingState
}
set {
guard internalExecutingState != newValue else { return }
willChangeValue(for: \CustomOperation.isExecuting)
internalExecutingState = newValue
didChangeValue(for: \CustomOperation.isExecuting)
}
}
override var isFinished: Bool {
get {
return internalFinishedState
}
set {
guard internalFinishedState != newValue else { return }
willChangeValue(for: \CustomOperation.isFinished)
internalFinishedState = newValue
didChangeValue(for: \CustomOperation.isFinished)
}
}
This implementation works perfectly on iOS 11 and 12, the system correctly removes my operations from the queue and start the other operations in the queue. (This is a 1 concurrent operation queue).
Issue:
But I discovered that this implementation using Keypath isn't working on iOS 10. No errors are triggered when doing the willChange/didChange
but the operations are never removed from the queue and so, the next operations are never getting started by the system.
After one hour of investigating this to understand the root cause of the issue, I discovered that if I notified through KVO using Strings instead of Keypath everything was working fine on both iOS 11/12 and iOS 10 (ie willChangeValue(forKey: "isExecuting")
instead of willChangeValue(for: \CustomOperation.isExecuting)
or willChangeValue(for : \.isExecuting)
)
Trying to find documentation for will/didChangeValue(for: Keypath)
I discovered this was a Swift only implementation without official Apple documentation since KeyPath doesn't exist in Objective-C and so resorted to read the Swift source code of the will/didChangeValue(for: KeyPath)
and discovered that internally the KeyPath were converted to String then passed to will/didChangeValue(forKey: String)
.
Is it possible that this conversion isn't working properly (due to a reason unknown to me) on iOS 10 ?
Thanks a lot.