Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instance properties defined by protocol on superclass are not autodiscovered #96

Open
freakboy3742 opened this issue Jan 13, 2018 · 1 comment
Labels
enhancement New features, or improvements to existing features.

Comments

@freakboy3742
Copy link
Member

On iOS, UITextField defines a keyboardType property. However, this property doesn't appear to get picked up by Rubicon.

Other properties (like borderStyle) work fine.

If you manually invoke send_message(obj, 'setKeyboardType:', ...), it works, too.

So - there's evidently something about the property discovery process.

A little digging revealed that the keyboardType() and setKeyboardType() accessor and mutator aren't found by cache_property_methods(). This may be due to the fact that they're defined on the UITextInputTraits protocol, rather than on a direct superclass of UITextField.

@dgelessus
Copy link
Collaborator

Hm, it seems like calls to keyboardType are handled dynamically. The keyboardType property does exist on UITextField, but there is no keyboardType method. Instead, UITextField overrides forwardingTargetForSelector:. When called with SEL("keyboardType") as an argument, it returns a UITextInputTraits object, which does have a statically provided keyboardType method. (The UITextInputTraits here is a class, apparently undocumented, and not the protocol of the same name.)

When calling a method with Rubicon using Python method call syntax, the method is looked up on the class (in the attribute access) and then called later (when the ObjCBoundMethod object is called). This doesn't work for dynamic methods, since they don't exist on the class. On the other hand, send_message uses objc_msgSend and friends to send a method call to the object directly, which triggers the whole dynamic method call process.

Here are some results of playing around with this in Pythonista (iPhone SE, iOS 10.3.3). I used this library that I wrote a while ago since it has better reflection/introspection support than Rubicon does at the moment. (Eventually I want to port that over to Rubicon, or implement something similar, when I have the time...)

>>> import objc
>>> objc.classes.UITextField
Out[0] = objc.api.Class('UITextField')
>>> objc.classes.UITextField.instance_properties_declared["keyboardType"]
Out[2] = <objc.api.Property 'keyboardType', attributes b'Tq,D,N'>
>>> objc.classes.UITextField.instance_methods_declared["keyboardType"]
Traceback (most recent call last): <snip>
builtins.KeyError: objc.api.Selector('keyboardType')
>>> objc.classes.UITextField.instance_methods["keyboardType"]
Traceback (most recent call last): <snip>
builtins.KeyError: 'keyboardType'
>>> tf = objc.classes.UITextField.new()
>>> tf.methods["keyboardType"]
Traceback (most recent call last): <snip>
builtins.KeyError: 'keyboardType'
>>> tf.keyboardType()
Traceback (most recent call last): <snip>
builtins.AttributeError: keyboardType
>>> tf.msg_send("keyboardType")
Traceback (most recent call last): <snip>
builtins.ValueError: No method found for selector b'keyboardType', cannot infer restype and argtypes
>>> tf.msg_send("keyboardType", restype="long long", argtypes=[])
Out[5] = 0
>>> tf.methods["keyboardType"]
Traceback (most recent call last): <snip>
builtins.KeyError: 'keyboardType'
>>> tf.forwardingTargetForSelector_(objc.Selector("keyboardType"))
Out[498] = <objc.api.ID wrapping UITextInputTraits at <cdata 'id_s *' 0x1741d1df0>: <UITextInputTraits : 0x1741d1df0>
public
   autocapitalization:                  2
   autocorrection:                      0
   spellchecking:                       0
   keyboard type:                       0
   kb appearance:                       0
   <snip>
>
>>> _.keyboardType()
Out[499] = 0

@freakboy3742 freakboy3742 added enhancement New features, or improvements to existing features. up-for-grabs labels Apr 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

2 participants