Search code examples
ipadioshtmlsafarihtml5-video

iOS Safari memory leak when loading/unloading HTML5 <video>


I've developed an iPad app with several UIWebViews that takes the following HTML and JavaScript. Since the iPad can only play one video at a time, I don't load the video until the particular web view is focused.

This is done by calling the stringByEvaluatingJavaScriptFromString method on the UIWebView, sending in a call to the JS method getFocus(). Similarly, when the web view is no longer needed I call lostFocus() to unload the video. This enables another UIWebView to play another video.

So far, so good. Everything works perfectly. Except for one thing: This causes a memory leak. Whenever viewing

I've tried reloading the UIWebView (instead of unloading the video with JS), that didn't work. I've also tried a zillion of different JavaScript variations, tag variations et cetera.

<div id="videoDiv"></div>

<script type="text/javascript">
    var movieDiv = document.getElementById('videoDiv'),
        movieHtml = '<video id="video" src="../Documents/<%= VideoFileName %>" width="768" height="911"></video>';

    var gotFocus = function () {
        movieDiv.innerHTML = movieHtml;
        var movie = document.getElementById('video');
        movie.play();
        movie.addEventListener('pause', function () {
            movie.currentTime = 0;
            movie.play();
        }, false);
    };
    var lostFocus = function () {
        movieDiv.innerHTML = '';
    };
</script>

Solution

  • I finally solved this! The solution was to empty the src and "load" a non-existing video. This causes no memory leak. Have a look:

    <div id="videoDiv"></div>
    
    <script type="text/javascript">
        var movieDiv = document.getElementById('videoDiv'),
            movieHtml = '<video id="video" src="" width="768" height="911"></video>';
    
        movieDiv.innerHTML = movieHtml;
        var movie = document.getElementById('video');
    
        var gotFocus = function () {
            movie.src = '../Documents/<%= VideoFileName %>';
            movie.load();
            movie.play();
            movie.addEventListener('pause', function () {
                movie.currentTime = 0;
                movie.play();
            }, false);
        };
        var lostFocus = function () {
            movie.src = '';
            movie.load(); // This line may be removed, see comments
        };
    </script>