progrium / darwinkit

Native Mac APIs for Go. Previously known as MacDriver
MIT License
4.99k stars 158 forks source link

ComboBox `SetDelegate` uses `TextField`'s `SetDelegte` resulting in error #223

Open corruptmemory opened 1 year ago

corruptmemory commented 1 year ago

Example:

items := []objc.IObject{
    foundation.NewStringWithString("a"),
    foundation.NewStringWithString("b"),
}

cb := appkit.NewComboBox()
cb.AddItemsWithObjectValues(items)

cbd := &appkit.ComboBoxDelegate{}
cb.SetDelegate(cbd)

Will fail at run time because the particular SetDelegate method invoked is this one:

func (t_ TextField) SetDelegate(value PTextFieldDelegate) {
    po0 := objc.WrapAsProtocol("NSTextFieldDelegate", value)
    objc.SetAssociatedObject(t_, objc.AssociationKey("setDelegate"), po0, objc.ASSOCIATION_RETAIN)
    objc.Call[objc.Void](t_, objc.Sel("setDelegate:"), po0)
}

And since we are giving it a ComboBoxDelegate instead of a TextFieldDelegate, the reflective type check fails.

I've built a work-around for this:

func setComboBoxDelegate(cb appkit.ComboBox, value appkit.PComboBoxDelegate) {
    po0 := objc.WrapAsProtocol("NSComboBoxDelegate", value)
    objc.SetAssociatedObject(cb, objc.AssociationKey("setDelegate"), po0, objc.ASSOCIATION_RETAIN)
    objc.Call[objc.Void](cb, objc.Sel("setDelegate:"), po0)
}

But needless to say, the current behavior isn't what a user would expect.

progrium commented 11 months ago

It is possible that generation would make a SetDelegate for ComboBox and skips it because it already exists in TextField, so that would be a generation bug. And your workaround is fine, but there is also always a generic Object version of any method that takes a Protocol interface, in this case SetDelegateObject.