Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-13497] iOS: app crashing on iPhone 4 when adding images to ScrollView

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionWon't Fix
Resolution Date2013-05-14T21:13:56.000+0000
Affected Version/sn/a
Fix Version/s2013 Sprint 10 API, 2013 Sprint 10
ComponentsiOS
LabelsSupportTeam, triage
ReporterDavide Cassenti
AssigneeVishal Duggal
Created2013-04-09T17:35:40.000+0000
Updated2017-03-22T22:55:28.000+0000

Description

Problem Description

Sample app taking pictures with camera and adding them in a ScrollView crashes on iPhone 4 after 7-8 images are added. The log shows a "Memory warning" message. No issues found with iPhone 5.

Test code

var damageImages = [];
var win = Ti.UI.createWindow({
    backgroundColor : '#fff'
});

var imageView = Ti.UI.createView({
        layout : 'horizontal',
        width : Ti.UI.FILL,
        height : Ti.UI.SIZE
    });

var successCallBack = function(e) {
    if (e.mediaType != Ti.Media.MEDIA_TYPE_PHOTO) {
        takePhotoBtn.enabled = true;
        pickPhotoBtn.enabled = true;
        return false;
    }

    var filename = (new Date().getTime()) + ".jpg";
    var newImageWrapperView = Ti.UI.createView({
            backgroundColor : '#000',
            left : '8dp',
            top : '10dp',
            height : '96dp',
            width : '96dp',
            isImage : true
    });
    newImageWrapperView.id = filename;
    var newImageView = Ti.UI.createImageView({
            isImage : true,
            zIndex : 10
    });
    newImageView.opacity = 0.5;
    newImageWrapperView.add(newImageView);

    var bgImage = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, filename);
    newImageView.image = bgImage.getNativePath();

    //I need this for let use..
    damageImages.push({
        "id" : bgImage.getNativePath(),
        "name" : filename,
        "description" : ""
    });

    //resizing code also removed
    /*
    var imageModify = Ti.UI.createImageView({
    image : e.media
    });
    var width = imageModify.toImage().width
    var height = imageModify.toImage().height
    imageModify = null;
    var scaledImage = require('lib/utils').resizeKeepAspectRatioNewWidth(e.media, width, height, Config.imageMaxWidth);
    */
    bgImage.write(e.media);
    //scaledImage = null;
    bgImage = null;
    imageView.add(newImageWrapperView);

    takePhotoBtn.enabled = true;
    pickPhotoBtn.enabled = true;
};

var errorCallBack = function(e) {
    takePhotoBtn.enabled = true;
    pickPhotoBtn.enabled = true;
    alert(L('erroronselectimage', 'Error while selecting image'));
};
var cancelCallBack = function(e) {
    takePhotoBtn.enabled = true;
    pickPhotoBtn.enabled = true;
};


var takePhotoBtn = Titanium.UI.createButton({
    style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
    title : 'Take Photo'
});

takePhotoBtn.addEventListener('click', function(e) {
    Ti.Media.showCamera({
        success : successCallBack,
        error : errorCallBack,
        cancel : cancelCallBack,
        allowEditing : false,
        saveToPhotoGallery : true,
        mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
    });
    takePhotoBtn.enabled = false;
    pickPhotoBtn.enabled = false;
});

var pickPhotoBtn = Titanium.UI.createButton({
    style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
    title : 'Pick Photo'
});

pickPhotoBtn.addEventListener('click', function(e) {
    Ti.Media.openPhotoGallery({
        success : successCallBack,
        error : errorCallBack,
        cancel : cancelCallBack,
        allowEditing : false,
        mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
    });
    takePhotoBtn.enabled = false;
    pickPhotoBtn.enabled = false;
});

var flexSpace = Titanium.UI.createButton({systemButton : Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE});

var toolbar = Ti.UI.iOS.createToolbar({
        borderTop : true,
        borderBottom : false,
        height : 45,
        zIndex : '100',
        bottom : '0dp'
    });
toolbar.items = [flexSpace, takePhotoBtn, pickPhotoBtn, flexSpace];


var scrollView = Ti.UI.createScrollView({
        layout : 'vertical',
        top : 0,
        bottom : 45
    });
    scrollView.add(imageView);
    win.add(scrollView);
    win.add(toolbar);

win.open();

Comments

  1. Davide Cassenti 2013-04-09

    During tests, devices even crashed entirely (e.g. reboot).
  2. Naga harish M 2013-04-10

    Hi, I tested with iPhone 4s and app is crashing most of the cases after taking 6-8 images using camera. I don't think this is problem with adding to Scrollview. Because app is crashing when we open the camera using showCamera only. Can you please make this high Priority. Thank you.
  3. Ashish Nigam 2013-04-10

    HI, Verified The issue with iPhone 5 also and Crashes on that also but number of images taken are quite high approx 30 to 35. **Device Crash Log**
       Incident Identifier: DD9157D8-314E-4EA2-825A-957D681B5A2D
       CrashReporter Key:   bd158f36569796279d86b0f6c5ca6b83e9c330f3
       Hardware Model:      iPhone5,1
       OS Version:          iPhone OS 6.0 (10A405)
       Kernel Version:      Darwin Kernel Version 13.0.0: Sun Aug 19 00:31:06 PDT 2012; root:xnu-2107.2.33~4/RELEASE_ARM_S5L8950X
       Date:                2013-04-10 14:55:31 +0530
       Time since snapshot: 1306 ms
       
       Free pages:        2738
       Active pages:      1306
       Inactive pages:    19709
       Throttled pages:   84705
       Purgeable pages:   251
       Wired pages:       149309
       Largest process:   conceptTest
       
       Processes
            Name                    <UUID>                       rpages       recent_max       [reason]          (state)
       
                assetsd <53881b88f0bf3948871456faf8fe5587>         1522             1522         [vm]         (daemon) (idle)
             MobileMail <7ddddc607bec3f1f9ac5212a22279714>         1355             1355                      (resume) (continuous)
            MobilePhone <3fefa53221ce3ccc867ade7d0f2b743a>         1300             1300                      (resume) (continuous)
                    kbd <98304e71b044348cbbc1fd3a7f0cda5a>          591              591                      (daemon)
                   tccd <96c9594f71b53a7fb5db7bd63ca52c90>          285              285                      (daemon)
            conceptTest <33514e224eeb36d182595067e925de72>       159731           160082  [per-process-limit] (frontmost) (resume)
                   ptpd <c03db1af00a7381ab52c2e01ec25e21c>         1094             1094                      (daemon)
            dataaccessd <0db5b1392b6c391496eaa9eff8122088>         1089             1089                      (daemon)
                syslogd <76c7ece27e1930ccba213a9ed4d6ead0>          187              187                      (daemon)
                  wifid <3c1b8ae2bd1f3453b8a34769c57a800a>          636              636                      (daemon)
          iaptransportd <589c47b3c06c3c8bb33b4044c6a94321>          355              355                      (daemon)
              locationd <5cca2615d1c23508808fd442ccf28470>         1263             1263                      (daemon)
           mediaserverd <80947eda91eb396d841f65d9deac2d76>        28835            28835                      (daemon)
                  timed <8984d2e17535329cbfd4baf3a9b8f963>          410              410                      (daemon)
                    lsd <e83b45e404e63cd785bf3e4a1780015f>          356              356                      (daemon)
            SpringBoard <b9e4c47e6285309aa0971087f76cb64c>         5622             5622                     
             backboardd <29faa2a7d1f1304c87418beb50a7e458>         5607             5607                      (daemon)
          fairplayd.N41 <185d84e38a5230ffaaa6b21cdcbb4754>          326              326                      (daemon)
              fseventsd <df4490b9277930f0b063da0f820fea5b>          351              351                      (daemon)
                imagent <b8a6dcb0b80d366bb8396f0eb131bacb>          436              436                      (daemon)
          mDNSResponder <8a128a0397f93f6f8ede1df8f60759a5>          354              354                      (daemon)
              lockdownd <66d819d22a643069b42aa2dbd7229db2>          396              396                      (daemon)
                 powerd <f60cc21c1b513b888db7563a2ad586ee>          240              240                      (daemon)
         UserEventAgent <4df6d63523a138f19d67bd59137827e1>          744              744                      (daemon)
        softwareupdated <ce42d24d6b2e3913914f06d5c2f5412d>          292              292                      (daemon)
           mobileassetd <f53eac44f107369ebf0ce64e9f051a44>          427              427                      (daemon)
       softwareupdatese <fcffee02207139fa875e7c52cb2032b0>          630              630                      (daemon)
       springboardservi <d5de7adf79053b1bb5850daf7abf2a53>            0                0                      (daemon)
             DTMobileIS <9d4add29c730382583f03d7a8df474cc>            0                0                      (daemon)
          absinthed.N41 <7d9923eda625387ba90685167a49c661>          139              139                      (daemon)
           mediaremoted <4f79c3873e8b35a3ab9c14b88131fc15>          398              398                      (daemon)
       filecoordination <5ca98b31b5d93b26a26c5011bc724908>          225              225                      (daemon)
       notification_pro <2dca4ba7b48c36e1a80c191034c70f70>          225              225                      (daemon)
                   afcd <58855a00a1dc3c99be7453efe0b5dfc7>          191              191                      (daemon)
              distnoted <79d66cd42c243074afe7bab01d31f354>          213              213                      (daemon)
                   apsd <6f919f4ed7a3353b89304db1493a6ffd>          449              449                      (daemon)
               networkd <305a7d187fce35d0bc48d0fbed74813e>          298              298                      (daemon)
             aggregated <756a686c7ee2314e8891549847e28db8>          132              132                      (daemon)
               BTServer <ab97543dbbb13651b170bb7a2d35ea3e>          419              419                      (daemon)
                configd <fb01e670ce773187a08ae6af05e81f19>          532              532                      (daemon)
             CommCenter <e4553263effe374e8480d4057c291b77>          795              795                      (daemon)
                notifyd <81c20c784ece3554a7a4bf7944a450ff>          230              230                      (daemon)
            ReportCrash <41677a971e73356db9dd24f1a6814432>          380              380                      (daemon)
       
       **End**
       
       
  4. Ashish Nigam 2013-04-10

    Hi, This particular line is interesting here, in the above device log. **conceptTest <33514e224eeb36d182595067e925de72> 159731 160082 [per-process-limit] (frontmost) (resume)**
  5. Vishal Duggal 2013-05-14

    The way the code is written the imageView loads the entire image into memory. The RGB data of the image occupies about 30 MB in VM (Use VM tracker on Instruments) So once you have taken about 8 photographs the app gets killed due to lack of memory. Given that the imageView is going to be at most 96x96 in size, it would be better to resize the image (keeping aspect ratio intact) and then use the resized image in the thumbnail view. The original image can be loaded later when needed. Code is attached below to show loading of scaled images. App no longer crashes. Scaling Logic
           var imgWid = e.media.width;
           var imgHt = e.media.height;
        
           var scaleW;
           var scaleH;
           if (imgWid > imgHt) {
               scaleW = 96;
               scaleH = Math.floor((imgHt * 96)/imgWid);
           } else {
               scaleH = 96;
               scaleW = Math.floor( (imgWid*96) /imgHt);
           }
        
           Ti.API.info(imgWid+' '+imgHt+' '+scaleW+' '+scaleH);
           newImageView.image = e.media.imageAsResized(scaleW, scaleH);
       
    Full Code
       var damageImages = [];
       var win = Ti.UI.createWindow({
           backgroundColor : '#fff'
       });
        
       var imageView = Ti.UI.createView({
               layout : 'horizontal',
               width : Ti.UI.FILL,
               height : Ti.UI.SIZE
           });
        
       var successCallBack = function(e) {
           if (e.mediaType != Ti.Media.MEDIA_TYPE_PHOTO) {
               takePhotoBtn.enabled = true;
               pickPhotoBtn.enabled = true;
               return false;
           }
        
           var filename = (new Date().getTime()) + ".jpg";
           var newImageWrapperView = Ti.UI.createView({
                   backgroundColor : '#000',
                   left : '8dp',
                   top : '10dp',
                   height : '96dp',
                   width : '96dp',
                   isImage : true
           });
           newImageWrapperView.id = filename;
           var newImageView = Ti.UI.createImageView({
                   isImage : true,
                   zIndex : 10
           });
           newImageView.opacity = 0.5;
           newImageWrapperView.add(newImageView);
        
           var bgImage = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, filename);
           //newImageView.image = bgImage.getNativePath();
       
           //I need this for let use..
           damageImages.push({
               "id" : bgImage.getNativePath(),
               "name" : filename,
               "description" : ""
           });
       
           var imgWid = e.media.width;
           var imgHt = e.media.height;
       
           var scaleW;
           var scaleH;
           if (imgWid > imgHt) {
               scaleW = 96;
               scaleH = Math.floor((imgHt * 96)/imgWid);
           } else {
               scaleH = 96;
               scaleW = Math.floor( (imgWid*96) /imgHt);
           }
       
           Ti.API.info(imgWid+' '+imgHt+' '+scaleW+' '+scaleH);
           newImageView.image = e.media.imageAsResized(scaleW, scaleH);
       
        
           //resizing code also removed
           /*
           var imageModify = Ti.UI.createImageView({
           image : e.media
           });
           var width = imageModify.toImage().width
           var height = imageModify.toImage().height
           imageModify = null;
           var scaledImage = require('lib/utils').resizeKeepAspectRatioNewWidth(e.media, width, height, Config.imageMaxWidth);
           */
           bgImage.write(e.media);
           //scaledImage = null;
           bgImage = null;
           imageView.add(newImageWrapperView);
        
           takePhotoBtn.enabled = true;
           pickPhotoBtn.enabled = true;
       };
        
       var errorCallBack = function(e) {
           takePhotoBtn.enabled = true;
           pickPhotoBtn.enabled = true;
           alert(L('erroronselectimage', 'Error while selecting image'));
       };
       var cancelCallBack = function(e) {
           takePhotoBtn.enabled = true;
           pickPhotoBtn.enabled = true;
       };
        
        
       var takePhotoBtn = Titanium.UI.createButton({
           style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
           title : 'Take Photo'
       });
        
       takePhotoBtn.addEventListener('click', function(e) {
           Ti.Media.showCamera({
               success : successCallBack,
               error : errorCallBack,
               cancel : cancelCallBack,
               allowEditing : false,
               saveToPhotoGallery : false,
               mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
           });
           takePhotoBtn.enabled = false;
           pickPhotoBtn.enabled = false;
       });
        
       var pickPhotoBtn = Titanium.UI.createButton({
           style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
           title : 'Pick Photo'
       });
        
       pickPhotoBtn.addEventListener('click', function(e) {
           Ti.Media.openPhotoGallery({
               success : successCallBack,
               error : errorCallBack,
               cancel : cancelCallBack,
               allowEditing : false,
               mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
           });
           takePhotoBtn.enabled = false;
           pickPhotoBtn.enabled = false;
       });
        
       var flexSpace = Titanium.UI.createButton({systemButton : Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE});
        
       var toolbar = Ti.UI.iOS.createToolbar({
               borderTop : true,
               borderBottom : false,
               height : 45,
               zIndex : '100',
               bottom : '0dp'
           });
       toolbar.items = [flexSpace, takePhotoBtn, pickPhotoBtn, flexSpace];
        
        
       var scrollView = Ti.UI.createScrollView({
               layout : 'vertical',
               top : 0,
               bottom : 45
           });
           scrollView.add(imageView);
           win.add(scrollView);
           win.add(toolbar);
        
       win.open();
       
  6. Lee Morris 2017-03-22

    Closing ticket as "Won't Fix".

JSON Source