Sunday, March 05, 2006

Fun with delegates

I just figured out an interesting little bug in my code. I had a view bound to a datapath. There were multiple items in the datapath, so there were multiple views created. My code looked like this (I haven't tested it, I've trimmed down my own code to get to the bare bones of the problem):

<MyItem datapath="resource-url/text()">
   <button onclick="startTimer()">
     <method name="startTimer()">
     parent.play(); // play resource
     if ("undefined" == typeof canvas.forwardDelegate) {
       canvas.forwardDelegate = new LzDelegate( parent, "forward" );
       LzTimer.addTimer( canvas.forwardDelegate, 1 );
     } else {
       LzTimer.resetTimer( canvas.forwardDelegate, 1 );
     }
     </method>
   </button>
   <method name="forward">
     Debug.write("forward: this.playing = " + this.playing);
   </method>
</MyItem>

Why I attached the delegate to the canvas is beyond me at this point; I think originally I was having problems accessing the delegate from other methods and I decided that stashing it in the canvas was a good idea. But the problem is the implied loop going on in the code (at the level where datapath is declared) - where forwardDelegate was getting attached over and over again to canvas.

When testing the code, I'd hit the button on each instance of MyItem, and I'd find one case where Debug.write said the resource was playing, but in the other cases they weren't! I didn't understand it because I knew empirically that the resource was actually playing. It was as if the "forward" method had some problem with it... and it did.

What was happening, I think, was that there was only one delegate pointing to a single instance method of "forward." The other delegates were getting overwritten (I assume) during the loop. So the resource was being played when I hit the button, all right; but when forwardDelegate called the "forward" method, it was not the "forward" method of the instance currently playing. Rather it was the "forward" method of a view whose resource was currently not playing.

This is the new code, which works as intended:

<MyItem datapath="resource-url/text()">
   <button onclick="startTimer()">
     <method name="startTimer()">
     parent.play(); // play resource
     if ("undefined" == typeof parent.forwardDelegate) {
       parent.forwardDelegate = new LzDelegate( parent, "forward" );
       LzTimer.addTimer( parent.forwardDelegate, 1 );
     } else {
       LzTimer.resetTimer( parent.forwardDelegate, 1 );
     }
     </method>
   </button>
   <method name="forward">
     Debug.write("forward: this.playing = " + this.playing);
   </method>
</MyItem>

0 Comments:

Post a Comment

<< Home