Uploaded image for project: 'Titanium SDK/CLI'
  1. Titanium SDK/CLI
  2. TIMOB-12399

iOS: No reliable way to remove all children from a proxy, and know when they are gone

    Details

      Description

      problem

      There's no reliable way to know when you remove all the children from a view if the children are actually gone from the view hierarchy in iOS. The remove() call in JS executes synchronously, but behind the scenes in iOS, the actual removal of the elements from UI appears to happen asynchronously. Take this sample code:

      var win = Ti.UI.createWindow({
      	backgroundColor: '#fff',
      	fullscreen: false,
      	exitOnClose: true
      });
      win.open();
       
      // add a stack of views
      for (var i = 0; i < 25; i++) {
      	win.add(Ti.UI.createView());	
      }
       
      // timeout is necessary since the add() appears to be async too
      setTimeout(function() {
      	// remove all, showing the child number
      	while(win.children.length) {
      		win.remove(win.children[0]);
      		Ti.API.info('kids left: ' + win.children.length);
      	}
      }, 2000);
      

      The output will vary, but often times you will see that the number of children on the win has not been reduced yet, because the child hasn't actually yet been removed from the win on the native side. Here's a sample output, notice the staggering of the decrementing around 23 and 10 due to the asynchronous removal:

      [INFO] :  kids left: 25
      [INFO] :  kids left: 23
      [INFO] :  kids left: 23
      [INFO] :  kids left: 21
      [INFO] :  kids left: 20
      [INFO] :  kids left: 19
      [INFO] :  kids left: 18
      [INFO] :  kids left: 17
      [INFO] :  kids left: 16
      [INFO] :  kids left: 15
      [INFO] :  kids left: 14
      [INFO] :  kids left: 13
      [INFO] :  kids left: 12
      [INFO] :  kids left: 11
      [INFO] :  kids left: 10
      [INFO] :  kids left: 10
      [INFO] :  kids left: 8
      [INFO] :  kids left: 7
      [INFO] :  kids left: 6
      [INFO] :  kids left: 5
      [INFO] :  kids left: 4
      [INFO] :  kids left: 3
      [INFO] :  kids left: 2
      [INFO] :  kids left: 1
      [INFO] :  kids left: 0
      

      It's worth noting that a safer way to remove these children would be in reverse order, as it won't be necessary for the index to change:

      for (var i = win.children.length-1; i >= 0; i--) {
      	win.remove(win.children[i]);
      }
      

      This doesn't solve the problem, though, of not knowing when these operations complete. If I was to remove 100 views from win and then add a bunch of new ones to it right after, chances are that some of those views will be added before all of the prior views were actually removed, causing some seriously weird runtime behavior. I've seen this in practice implementing data binding in Alloy. When a Collection of data changes, I need to re-render a section of the UI, removing all its views, and replacing them with the updated data. This is where this problem surfaces constantly for me. I'm sure there are many other use cases.

      It is also worth nothing that this problem does not occur on Android. Android appears to process these remove and add calls synchronously making for a simple, safe "remove all" operation.

      proposed solution

      • Make the remove() and add() calls synchronous. I'm going to assume this isn't going to be possible in concern for performance. That said, it is a parity issue with Android as the remove() API behaves differently on the separate platforms.
      • Provide some means of knowing when the remove() call is actually complete, perhaps a callback that can fire when the operation is done.
      • A new API, a synchronous setChildren() function that can take an array of child elements. Not only would this allow you to safely remove all elements then add more directly after, but it would also increase overall performance by allowing you to make fewer jumps into native-land when establishing a view hierarchy.

      All of these are off the top of my head, or based on a conversation with Blain Hamon. I'm open to anything that allows me to empty a view of all children and know when that operation is complete, preferably in a cross-platform manner.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                vduggal Vishal Duggal (Inactive)
                Reporter:
                tlukasavage Tony Lukasavage
                Reviewer:
                Pedro Enrique (Inactive)
              • Watchers:
                0 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Backbone Issue Sync

                  • Titanium SDK/CLI <> Titanium Mobile
                    Synced with:
                    TIMOB-15407
                    Sync status:
                    ERROR
                    Last received:
                    Last sent:

                    Git Source Code