I'm trying to set a click listener programmaticall...
# kotlin-native
s
I'm trying to set a click listener programmatically in an iOS application, and I'm getting an error because I'm setting the bridge incorrectly. What should the value be for the bridge?
Copy code
@ExportObjCClass
class ViewController : UIViewController {
    constructor(aDecoder: NSCoder) : super(aDecoder)
    override fun initWithCoder(aDecoder: NSCoder) = initBy(ViewController(aDecoder))

    @ObjCOutlet lateinit var label: UILabel

    @ObjCOutlet lateinit var textField: UITextField

    @ObjCOutlet lateinit var button: UIButton

    override fun viewDidLoad() {
        super.viewDidLoad()

        button.addTarget(this, action=sel_registerName("buttonPressed"), forControlEvents=UIControlEventTouchDown)
    }

    @ObjCMethod(selector = "buttonPressed", bridge = "ViewController") fun buttonPressed() {
        label.text = "Konan says: '2, ${textField.text}!'"
    }
}
v
If you replace the entire
@ObjCMethod
annotation with
@ObjCAction
, like in the sample, it seems to work.
s
It does. Why does it work?
v
Let's ask @svyatoslav.scherbina
s
I'm also interested why something like this won't work to make click listeners easier...
Copy code
@ExportObjCClass
class ViewController : UIViewController {
    constructor(aDecoder: NSCoder) : super(aDecoder)
    override fun initWithCoder(aDecoder: NSCoder) = initBy(ViewController(aDecoder))

    @ObjCOutlet lateinit var label: UILabel

    @ObjCOutlet lateinit var textField: UITextField

    @ObjCOutlet lateinit var button: UIButton

    override fun viewDidLoad() {
        super.viewDidLoad()

        button.onClick {
            label.text = "Konan says: 'Hello, ${textField.text}!'"
        }
    }
}

fun UIButton.onClick(onClick: () -> Unit) {
    val handler = ClickHandler(onClick)
    this.addTarget(handler, sel_registerName("buttonPressed"), UIControlEventTouchUpInside)
}

@ExportObjCClass
class ClickHandler(private val onClick: () -> Unit) {
    @Suppress("unused")
    @ObjCAction fun buttonPressed() {
        onClick()
    }
}
s
It does. Why does it work?
@ObjCMethod
annotation is not supposed to be applied this way, thus it doesn’t work.
@ObjCAction
annotation is designed for this case, so it works.
I’m also interested why something like this won’t work to make click listeners easier...
Your code has a couple of issues: 1)
ClickHandler
should extend
NSObject
class 2)
addTarget
requires the target object (
handler
in your case) to be stored somewhere to prevent from being removed:
The control does not retain the object in the target parameter. It is your responsibility to maintain a strong reference to the target object while it is attached to a control.
So you can create a list of handlers in
ViewController
and add all handlers to that list. The list should be cleared when view is being unloaded, because otherwise you would leave a cycle of objects referencing each other with strong references, and since that cycle would contain Objective-C object (
ViewController
), it would not be deleted by Kotlin/Native garbage cycle collector. By the way, it is not necessary to add
@ExportObjCClass
to
ClickHandler
.
s
Thanks for the help. I was able to get it working. 🙂 Something tells me that I'm going to find a lot of little things like this very annoying coming from Android to iOS.