-
Notifications
You must be signed in to change notification settings - Fork 22
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
Building a Native Extension - mandatory callback gotcha #306
Comments
This is a bug, not a feature, IMO! Unfortunately, it is not the setting of mandatory vs. optional callback that determines the behavior. It occurs even with optional callback, so long as a callback is provided. If a callback is given (at least a lambda callback) then property values read immediately after the call will not be correct, unless a callback is used to read the property values. This should be called-out in the documentation until/unless this is fixed. |
With callback. Note that returned properties are incorrect, except for the last case, where I used a callback to retrieve the property values. Note: the def test_bonjour_browser
# Note: default service type is '_http._tcp_.', default domain is '.local'
Rho::BonjourBrowser.start( {serviceType: '_appletv-v2._tcp.', domain: ''}, lambda do |callback_data|
{{#logInfo}} "got callback from Rho::BonjourBrowser.search callback_data = #{callback_data.inspect}" {{/logInfo}}
end # lambda
)
{{#logInfo}}
[
"Rho::BonjourBrowser.serviceType = #{Rho::BonjourBrowser.serviceType.inspect}",
"Rho::BonjourBrowser.domain = #{Rho::BonjourBrowser.domain.inspect}",
"Rho::BonjourBrowser.getProperty('serviceType') = #{Rho::BonjourBrowser.getProperty('serviceType').inspect}",
"Rho::BonjourBrowser.getProperty('domain') = #{Rho::BonjourBrowser.getProperty('domain').inspect}",
"Rho::BonjourBrowser.getAllProperties = #{Rho::BonjourBrowser.getAllProperties.inspect}",
"Rho::BonjourBrowser.getProperties(['serviceType', 'domain']) = #{Rho::BonjourBrowser.getProperties(['serviceType', 'domain']).inspect}"
]
{{/logInfo}}
Rho::BonjourBrowser.getAllProperties( lambda do |p|
{{#logInfo}}
"lambda property getter test: #{p.inspect}"
{{/logInfo}}
end )
redirect action: :index, query: {msg: 'searching for services'}
end
|
With no callback, properties are as expected: def test_bonjour_browser
# Note: default service type is '_http._tcp_.', default domain is '.local'
Rho::BonjourBrowser.start( {serviceType: '_appletv-v2._tcp.', domain: ''} )
{{#logInfo}}
[
"Rho::BonjourBrowser.serviceType = #{Rho::BonjourBrowser.serviceType.inspect}",
"Rho::BonjourBrowser.domain = #{Rho::BonjourBrowser.domain.inspect}",
"Rho::BonjourBrowser.getProperty('serviceType') = #{Rho::BonjourBrowser.getProperty('serviceType').inspect}",
"Rho::BonjourBrowser.getProperty('domain') = #{Rho::BonjourBrowser.getProperty('domain').inspect}",
"Rho::BonjourBrowser.getAllProperties = #{Rho::BonjourBrowser.getAllProperties.inspect}",
"Rho::BonjourBrowser.getProperties(['serviceType', 'domain']) = #{Rho::BonjourBrowser.getProperties(['serviceType', 'domain']).inspect}"
]
{{/logInfo}}
Rho::BonjourBrowser.getAllProperties( lambda do |p|
{{#logInfo}}
"lambda property getter test: #{p.inspect}"
{{/logInfo}}
end )
redirect action: :index, query: {msg: 'searching for services'}
end
|
I guess the documentation advice would be that if you provide a callback to a method, and that method also merges some passed properties into the object properties, then the only reliable way to read the properties immediately after the call is by using the callback method of property retrieval. |
If a callback is provided then the call will be asynchronous, if the callback is absent then the method will be called synchronously. The behaviour as described sounds reasonable, if calling asynchronously then the developer should only expect the method to complete after the callback is received. This should definitely be documented however, I thought it was but checking the documentation I don't see any mention of it. @michaelToews , I can provide internal design documentation into how the callback mechanism works if it helps documenting this externally. Thanks. @rognar for visibility |
There is a "gotcha" with API callbacks that should be pointed-out. Note: at first, I thought this was an issue only with mandatory callbacks. No. It is just an issue with callbacks, period. Note also I noticed when while creating a native extension, but I think it applies more generally to all APIs using the new 4.x API scheme.
If a method that has a callback (and callback was supplied) changes some object properties (perhaps via a
propertyMap
parameter, etc.), and then, subsequent to return, the caller examines object properties, (with any method other than callback) then the property values returned will be incorrect. They will be the property values before the call to the method.This is true at least for iOS and when the method is called from a Rhodes controller. It seems the property values will not be read correctly within the controller instance. (Keep in mind that controller instances exist only for a single request/response.)
If you examine properties with a lambda callback, you will find they have correct values. Of course, the callback is called after the controller instance terminates. As well, if you examine the properties in a different controller instance, then they will be correct.
In my own extension, then, I've avoided using a mandatory callback. It is a better design anyway. I am writing an extension for Bonjour service discovery. As services are discovered, you get callbacks. But it is useful, as well, to have no callbacks, and then just come back later and examine an array property with results. So, when possible, it's good design to avoid requiring a mandatory callback, and, at the same time, it solves this asynchronous problem with properties.
I'm not sure if this is "a bug or a feature"!
The text was updated successfully, but these errors were encountered: