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

fix(ios): avoid leaking objects in hasProperty callback #10524

Merged
merged 7 commits into from
Dec 12, 2018

Conversation

janvennemann
Copy link
Contributor

@janvennemann janvennemann commented Dec 10, 2018

JIRA: https://jira.appcelerator.org/browse/TIMOB-26452

Optional Description:
This fixes two issues at once:

  1. TIMOB-26452: Incorrect reporting of false when property's value is null
  2. TIMOB-26391: Continued reports about app crashes in 7.5.0 were caused by the introduction of the hasProperty callback in [TIMOB-26179] Check for property existence using hasProperty #10150 and hanging JSValueRefs that were not added to the JS object graph after retrieval. This reworks the whole implementation by checking for all the magic that is happening in - (id)valueForKey:(NSString *)key and just returning true or false without accessing the actual value of the property.

@sgtcoolguy This introduces some duplicate code since the checks are now done in hasProperty and in valueForKey. I have some ideas how to resolve this by isolating the checks and match them with an enum. We would then just check for the enum's value and perform the appropriate actions in both methods. However, i didn't want to refactor too much of the existing code in such a critical point of our core. We might want to pair this with setter and getter removal in 9.0.0 when we need to touch valueForKey anyway.

@build
Copy link
Contributor

build commented Dec 10, 2018

Messages
📖

💾 Here's the generated SDK zipfile.

Generated by 🚫 dangerJS

Copy link
Contributor

@sgtcoolguy sgtcoolguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes LGTM. I'd really like to see some changes to the test suite to sanity check this.

Ideally just a handful of spot-checks on our proxies that they respond properly to each of these cases. You do a nice job enumerating them in the doc string there.

@janvennemann
Copy link
Contributor Author

@sgtcoolguy added tests to verify the property checks. This revealed some differences between Android and iOS we might want to fix for parity.

describe('Submodules', () => {
it('should check for sub-module', () => {
Ti.should.have.property('UI');
// @fixme this check throws an error on android
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way to mark this in the test is to do it.androidBroken('should check for sub-module', () => {

});

describe('Custom properties', () => {
it.ios('should check for custom properties', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why limit this to iOS only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Android throws an error when doing .not.have.property checks directly on modules. I'll mark it as it.androidBroken together with the other one above.


it.ios('should check for dynamic getter method', () => {
const view = Ti.UI.createView();
view.should.have.property('getFoo');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should this pass? It shouldn't respond true here as there is no "foo" property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's iOS getter/setter magic. It first tries to find an actually existing property on the proxy and tries to set that. If not found, it will fallback to set it as a "dynamic property" on the proxy. So everything starting with set or get is automatically available on iOS.

https://github.com/appcelerator/titanium_mobile/blob/abc04066bd0ec9ac29066ba9a3b46fb489d51044/iphone/TitaniumKit/TitaniumKit/Sources/API/TiProxy.m#L1100

This results in these statements being equivalent on iOS:

view.foo = 'bar';
console.log(view.foo);
view.setFoo('bar');
console.log(view.getFoo());


it.ios('should check for dynamic setter method', () => {
const view = Ti.UI.createView();
view.should.have.property('setFoo');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, why does this pass? This looks like a bug to me, there's no foo property.

@janvennemann
Copy link
Contributor Author

@sgtcoolguy marked the two tests as broken on android. For the weird/magical iOS behavior see my other comment.

@lokeshchdhry lokeshchdhry merged commit 1eddbb4 into tidev:master Dec 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants