Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 6ba3f89

Browse files
committed
fix early release of KVO observer
1 parent 35af4db commit 6ba3f89

File tree

4 files changed

+33
-15
lines changed

4 files changed

+33
-15
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
kotlinVersion = "1.8.10"
33

4-
mokoWidgetsVersion = "0.2.3"
4+
mokoWidgetsVersion = "0.2.4"
55
mokoResourcesVersion = "0.21.2"
66
mokoMvvmVersion = "0.16.0"
77
mokoFieldsVersion = "0.12.0"

widgets/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ kotlin {
3838
this as org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
3939

4040
compilations.getByName("main") {
41-
val pluralizedString by cinterops.creating {
42-
defFile(project.file("src/iosMain/def/objcAddtition.def"))
41+
val objcAddition by cinterops.creating {
42+
defFile(project.file("src/iosMain/def/objcAddition.def"))
4343
}
4444
}
4545
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ void setAssociatedObject(id object, id value) {
2020
return objc_setAssociatedObject(object, &kAssociatedObjectKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2121
}
2222

23+
void setAssociatedObjectWithKey(id object, NSValue* key, id value) {
24+
return objc_setAssociatedObject(object, key.pointerValue, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
25+
}
26+
2327
NSArray* cgColors(NSArray<UIColor*>* uiColors) {
2428
NSMutableArray* result = [NSMutableArray arrayWithCapacity: uiColors.count];
2529
for(int i = 0;i < uiColors.count;i++) {

widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/core/utils/UIControlExt.kt

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
package dev.icerock.moko.widgets.core.utils
66

77
import dev.icerock.moko.widgets.objc.KeyValueObserverProtocol
8+
import dev.icerock.moko.widgets.objc.setAssociatedObjectWithKey
89
import kotlinx.cinterop.COpaquePointer
10+
import kotlinx.cinterop.ExportObjCClass
911
import kotlinx.cinterop.ObjCAction
1012
import kotlinx.cinterop.cstr
1113
import platform.Foundation.NSKeyValueObservingOptionNew
1214
import platform.Foundation.NSSelectorFromString
15+
import platform.Foundation.NSString
16+
import platform.Foundation.NSValue
17+
import platform.Foundation.UTF8String
1318
import platform.Foundation.addObserver
19+
import platform.Foundation.valueWithPointer
1420
import platform.UIKit.UIControl
1521
import platform.UIKit.UIControlEvents
1622
import platform.UIKit.UIGestureRecognizer
@@ -58,24 +64,28 @@ fun UIGestureRecognizer.setHandler(action: () -> Unit) {
5864
)
5965
}
6066

67+
private val keys = mutableMapOf<String, NSValue>()
68+
6169
fun <V : UIView, CTX> V.observeKeyChanges(
6270
keyPath: String,
6371
context: CTX,
6472
action: (V, CTX) -> Unit
6573
) {
66-
val ref: WeakReference<V> = WeakReference(this)
67-
68-
val target = ObserverObject {
69-
val strongRef: V = ref.get() ?: return@ObserverObject
74+
val target: ObserverObject<V> = ObserverObject(this) {
75+
action(this, context)
76+
}
7077

71-
action(strongRef, context)
78+
val keyString = "observeKeyChanges-$keyPath"
79+
val key: NSValue = keys[keyString] ?: let {
80+
NSValue.valueWithPointer((keyString as NSString).UTF8String)
81+
}.also {
82+
keys[keyString] = it
7283
}
7384

74-
objc_setAssociatedObject(
85+
setAssociatedObjectWithKey(
7586
`object` = this,
76-
key = "observeKeyChanges-$keyPath".cstr,
77-
value = target,
78-
policy = OBJC_ASSOCIATION_RETAIN
87+
key = key,
88+
value = target
7989
)
8090

8191
this.addObserver(
@@ -86,17 +96,21 @@ fun <V : UIView, CTX> V.observeKeyChanges(
8696
)
8797
}
8898

89-
private class ObserverObject(
90-
private val lambda: () -> Unit
99+
@ExportObjCClass
100+
private class ObserverObject<T : Any>(
101+
ref: T,
102+
private val lambda: T.() -> Unit
91103
) : NSObject(), KeyValueObserverProtocol {
104+
private val ref: WeakReference<T> = WeakReference(ref)
92105

93106
override fun observeValueForKeyPath(
94107
keyPath: String?,
95108
ofObject: Any?,
96109
change: Map<Any?, *>?,
97110
context: COpaquePointer?
98111
) {
99-
lambda()
112+
val strongRef: T = ref.get() ?: return
113+
lambda.invoke(strongRef)
100114
}
101115
}
102116

0 commit comments

Comments
 (0)