nwebb

Flex, Flash, AIR

One Reason Why Your Flex Getter May Not Execute

I ran in to a nasty little bit of behaviour [bug?] with a pair of bindable getter/setter methods today, and it's something you should proabably make yourself aware of because it's pretty easy to run in to and not immediately obvious what the cause is.

Problem
The code in my setter method was only being run the very first time the method was called. After that it didn't run at all - I was stumped.

I placed a breakpoint at the first line of the setter, and then on the second line (which was just a curly brace), and the third line ... you get the picture. The first breakpoint was always triggered, but the second and third breakpoints only got 'hit' the first time I called the setter - after that they were completely ignored. So, the code didn't appear to be the problem. I placed a trace at the beginning of the setter and even that got ignored after the first run.

Issue
Normally, when I create a setter method it looks something like:

Actionscript:
  1. [Bindable]
  2. public function set someValue(value:Object):void
  3. {
  4.         if(value != _someValue)
  5.         {
  6.                 //code here...
  7.         }
  8. }

... but on this occassion I had some logic which I wanted to execute even if the value being sent in was the same as last time, and this works fine ... until you make the getter/setter bindable

Cause
As soon as you make the getter/setter bindable, Flex stops running the setter whenever the value you're sending in already matches the value that the corresponding getter will return.

Solution
The solution (or at least one solution) is not to rely upon the default propertyChange event which is dispatched for bindable values, and instead create/dispatch a custom event like so:

Actionscript:
  1. [Bindable(event="someValueChange")]
  2. public function set someValue(value:Object):void
  3. {
  4.        //code here... this will run regardless
  5.         if(_someValue != value) _someValue = value;
  6.         dispatchEvent(new Event("someValueChange"));
  7. }
  8.  
  9. public function get someValue():Object
  10. {
  11.         return _someValue;
  12. }

This ensures that the setter is run regardless. My problem was that the second time I called the setter I was (you guessed it) passing in the same value as the getter was already returning.

I'm sure the reason the setter's ignored is performance-related, and using a custom event is no big deal - the issue was actually working out what was causing this behaviour in the first place.

The issue was also reported by Tony Hillerson ( thanks to Tony and the guys on his blog who left comments, for identifying the cause and saving me some time =) )

16 Comments so far

  1. Matt July 23rd, 2008 6:31 pm

    Yes, this is performance related. Especially at startup when components are being created bindings will execute repeatedly. We wanted to make sure that we weren’t the cause of slower startup just because of binding. Your workaround is good, I don’t know if we have anything in the docs that call this out specifically.

  2. nwebb July 23rd, 2008 9:48 pm

    Hi Matt, completely understandable and thanks kindly for the clarification.

    I don’t recall seeing mention of it in the docs and it would certainly be a useful addition.

  3. jon July 28th, 2008 3:37 am

    Thank you for posting this! I’ve been stumped on this for hours and it was driving me insane! I hope to heck Adobe puts this into their docs, can’t believe that it’s not in there already since it’s a major headache without an obvious reason. Thanks again!

  4. Farof September 25th, 2008 1:09 pm

    Thank’s for this usefull article ! It’s the first one I found talking about the [Bindable] annotation, saved me lots of time.
    Guess I’m going to sneak around your blog to find other useful tips.

  5. RinKaMeAri January 21st, 2009 9:32 am

    Thanks for this workaround!
    Btw, it seems flex docs were updated because this case is described in “Data Access and Interconnectivity”/ “Binding Data”/”Using the Bindable metadata tag”, second case of “Bindable” usage.

  6. RinKaMeAri January 21st, 2009 9:33 am

    Thanks for this workaround!
    Btw, it seems flex docs were updated because this case is described in “Data Access and Interconnectivity”/ “Binding Data”/”Using the Bindable metadata tag”, third case of “Bindable” usage.

  7. Douglas McCarroll August 1st, 2009 9:56 pm

    1. Thanks Neil! This info is almost impossible to find. I’ve added an note, and link to this post, in the relevant Jira at http://bugs.adobe.com/jira/browse/SDK-12537 so that others can find it a bit more easily.

    2. People may want to only dispatch the event *if* the value is actually changed. There’s no need to trigger the binding mechanism if it isn’t, or at least I can’t think of a case where you would want it dispatched.

    3. Finally, I’m going to add some keywords that would have allowed me to find this post much more quickly. I had to spent a good hour Googling before I came across it. :) “doesn’t execute” “setter method” “same” “actionscript” “flex” “value” “getters” “setters” “implicit”

    Thanks again,

    Douglas

  8. [...] nwebb ยป One Reason Why Your Flex Getter May Not Execute CauseAs soon as you make the getter/setter bindable, Flex stops running the setter whenever the value you’re sending in already matches the value that the corresponding getter will return. [...]

  9. John Uckele October 5th, 2009 6:07 pm

    This is actually very interesting. I’ve been fretting about the possibility of loops caused by data binding executing on null changes. Not that I know this isn’t actually possible that alleviates my concerns significantly.

  10. Zmoky November 12th, 2009 12:21 pm

    This set/get issue gave my huge headache until I’ve discovered that it doesn’t execute if the value that is set is the same. I’ve used a lot of other frameworks and programming languages and I can say that this is a very big stupid problem along others that I’ve found during my flex developing and I think that adobe should seriously consider their programming techniques

  11. johans December 7th, 2009 4:41 am

    This also had me stumped for some time.

    But here’s a strange thing - I’m using Flex 4 and I can add any name for the event in the Bindable metadata - [Bindable(event="foo")], not dispatch ANY event from the setter, and it will work.

    As soon as I remove the event from the Binding metadata making it [Bindable] it does not work.

  12. nwebb December 7th, 2009 10:21 am

    Hi Johans,
    ah, that’s actually expected behaviour (in Flex 2/3 too).
    Flex doesn’t perform any checks to ensure the event is getting dispatched. When you use the default [Bindable] tag, Flex is dispatching an event for you in the background, but that’s it … no checks if I remember correctly. As soon as you tell the compiler that you’re going to dispatch a custom event type, it no longer dispatches the default (PROPERTY_CHANGE) for you, and the onus is on you to dispatch the event; I guess checking that an event has been dispatched would be complex if not impossible - you may not necessarily want to dispatch the event from the setter (or maybe you’ll want to dispatch it from the setter and other places).

    Essentially by declaring a custom eventType you are bypassing some of the code that would otherwise be written for you, and (apart from the event being dispatched), one of those things is a conditional which won’t allow the value to be set if the new value being passed in is the same as the existing one.

    Cheers,
    Neil

  13. johans December 7th, 2009 7:40 pm

    Hi Neil - thank you for explaining. I would have thought the compiler could check that every event listener had at least one corresponding dispatcher and vice versa. Thanks again.

  14. [...] It’s worth noting that the auto-generated code also performs a check, only updating the value if the value being set is different to the current value (see One Reason Why Your Flex Getter May Not Execute) [...]

  15. Anang A Phatak January 26th, 2010 2:49 am

    Can you explain why you would do this ?
    Why are you making a setter function bindable ?
    Wouldn’t you be better served by making the variable bindable when you declare it for the class ?

    Strange problem, thanks for the solution, but hard to see where it would apply

  16. nwebb January 26th, 2010 8:08 am

    @Anang - Sure. First of all, just to clarify - putting a bindable tag above either the implicit getter or implicit setter makes both the getter & setter bindable.

    From the outside of your class it looks as if a variable is being set, yet inside your class you are calling a method (and so you can perform checks / run more complex logic as needed). The great thing about implicit getter/setters is the ability to put them in place of existing public variables without changing the api of your class - this is unlike many other languages, where you cannot change a variable such as “label” for a method call such as setLabel() without changing the call that other classes need to make.

    You could just make a variable bindable, but you lose the ability to perform complex logic (which in some cases is quite acceptable), but behind the scenes guess what Flex is doing … yep, it is creating a getter/setter for you anyway ( you can see this for yourself by setting a compiler option called -keep-generated-actionscript and looking through the ’src.generated’ folder which is then created, for a class called _[yourProjectName]-binding-generated ).

    It is also very common to use bindable getter/setters throughout the Flex framework. You can take a look inside the standard Flex classes where you will see this being used a lot (eg Button -> get/set label)

    I hope this answers your question.
    Cheers,
    Neil

Leave a reply

Bad Behavior has blocked 1077 access attempts in the last 7 days.