Reputation: 2494
I'm trying to use RxSwift for binding in MVVM.
I have a Enum
:
enum Color : Int {
case Red = 0, Green
}
and class for test
class Test : NSObject {
var color: Color = .Red
dynamic var test: String? {
didSet {
print("didSet \(test)")
}
}
}
And want to observe changes like:
test.rx_observe(Color.self, "color").subscribeNext { (color) -> Void in
print("Observer \(color)")
}.addDisposableTo(bag)
But the program chashes with
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<RDProject.Test 0x7ff373513020> addObserver:<RxCocoa.KVOObserver 0x7ff37351a420> forKeyPath:@"color" options:5 context:0x0] was sent to an object that is not KVC-compliant for the "color" property.'
Code for simple String
works:
test.rx_observe(String.self, "test").subscribeNext { string in
print("Observer \(string)")
}.addDisposableTo(bag)
test.test = "1"
test.test = "2"
I found here that to make class inherited not from NSObject
I should make it dynamic
, but I can't make Enum
dynamic.
Is there a way to make Enum
observable?
Upvotes: 7
Views: 4321
Reputation: 56
If your applications's minimum supported version of iOS is 13.0 or newer you can use Combine and make the property @Published
class Test : NSObject {
@Published var color: Color = .Red
dynamic var test: String? {
didSet {
print("didSet \(test)")
}
}
}
and observe it like this:
let test = Test()
test.$color.sink(receiveValue: { color in
print(color)
})
Upvotes: 0
Reputation: 13661
Because your enum is of type Int
, you can make it objective-c compatible by marking it with @objc
. Doing this will make compiler ok with marking the property as dynamic
. For the property to be KVO compliant, it'll also need to be anotated with @objc
.
@objc enum Color : Int {
case Red = 0, Green
}
class Test : NSObject {
@objc dynamic var color: Color = .Red
dynamic var test: String? {
didSet {
print("didSet \(test)")
}
}
}
Upvotes: 2
Reputation: 1528
You don't need to use KVO for this task. Just use a BehaviorSubject like this:
Create a private Field like this one:
let colorSubject = BehaviorSubject<Color?>(value: nil)
Then you have a property like this which informs the BehaviorSubject that the value did change.
var color : Color? {
didSet {
colorSubject.onNext(color)
}
}
To subscribe to any change use an equivalent statement to this one:
let disposable = colorSubject.subscribeNext { (color: Color?) -> Void in
// Do something with it.
}
Upvotes: 5
Reputation: 10961
I can suggest only make a proxy variable and use KVO on it.
class Model: NSObject {
enum Color: Int {
case Red = 0, Green
}
dynamic var colorRaw: Int?
var color: Color = .Red {
didSet {
colorRaw = color.rawValue
}
}
}
More details here - https://christiantietze.de/posts/2015/05/observing-enum-swift-kvo/
Upvotes: 0