{ "id": "131637", "key": "TIMOB-17147", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": { "id": "7", "description": "", "name": "Invalid" }, "resolutiondate": "2017-05-02T22:07:40.000+0000", "created": "2014-06-12T07:20:02.000+0000", "priority": { "name": "Low", "id": "4" }, "labels": [ "community" ], "versions": [ { "id": "15971", "description": "Release 3.2.3", "name": "Release 3.2.3", "archived": false, "released": true, "releaseDate": "2014-04-30" } ], "issuelinks": [ { "id": "38336", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "131622", "key": "AC-1572", "fields": { "summary": "iOS: ScrollableView: cacheSize does not work if page views have children...", "status": { "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "name": "Resolved", "id": "5", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2017-05-02T22:07:40.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "The \"cacheSize\" property of the ScrollableView allows the developer to define how many \"pages\" are to be pre-rendered when the ScrollableView is loaded. As the user scrolls, additional pages are pre-redendered as needed. This is useful for complex scrollable views with many items as it increases performance and reduces memory use.\r\n\r\nProblem:\r\n\r\nIf the pages (views) contains child views, the cacheSize property does not work and all pages are pre-rendered at once. When loading hundreds of complex pages, this results on the ScrollableView becoming very slow as it is not taking advantage of the cache logic.\r\n\r\nTest case:\r\n\r\nThe code below shows this problem. You can set the TEST_CASE variable between 1 and 4 to test the four different cases.\r\n\r\nThe first two cases load only a single view control (a view, and an imageview). These two cases work, and as can be seen from the console log, only 3 pages are pre-rendered initially, and as you scroll additional pages are pre-rendered as needed. Remote images are loaded as needed as well.\r\n\r\nThe last two cases load views with children (3 = a view with a child imageview, and 4 = a view with a child view). As can be seen from the console, these two cases fail, as cacheSize is ignored and the ScrollableView pre-renders all 100 pages at once.\r\n\r\napp.js\r\n{code}\r\n// window\r\nvar win = Ti.UI.createWindow({\r\n title: 'TEST',\r\n backgroundColor: '#ffffff'\r\n});\r\n \r\n \r\n// returns array of remote images (from kitchensink)\r\nfunction getPhotos() {\r\n var data = [];\r\n var baseUrl = 'http://placehold.it/';\r\n var imageUrl;\r\n for (i=30;i<40;i++){\r\n for (j=30;j<40;j++){\r\n imageUrl = baseUrl+i+'x'+j;\r\n data.push(imageUrl);\r\n }\r\n } \r\n return data;\r\n}\r\n \r\n \r\n// load event for remote image\r\nfunction img_load(e) {\r\n Ti.API.info('Loaded remote image ' + e.source.id + ': ' +e.source.image);\r\n}\r\n \r\n \r\n// postlayout event for view\r\nfunction view_postlayout(e) {\r\n Ti.API.info('Post-layout ' + e.source.id);\r\n}\r\n \r\n \r\n// scrollable view with set cache size set to 3\r\nvar pager = Ti.UI.createScrollableView({\r\n cacheSize: 3\r\n});\r\n \r\n \r\n// assemble and open\r\nwin.add(pager);\r\nwin.open();\r\n \r\n \r\n//\r\n// TEST CASE SELECTOR (1, 2, 3 or 4)\r\n//\r\nvar TEST_CASE = 1;\r\n \r\n \r\n// simulate 2s delayed xhr call to bind scrollable view with data\r\nsetTimeout(function() {\r\n \r\n var photos = getPhotos(),\r\n pages = []; \r\n \r\n // TEST CASE BRANCH\r\n if (TEST_CASE == 1)\r\n {\r\n // CACHESIZE WORKS HERE: ONLY 3 VIEWS ARE LOADED\r\n \r\n // load empty container views\r\n for (var i = 0; i < photos.length; i++)\r\n { \r\n // container view\r\n var cont = Ti.UI.createView({ id: i, width: 300, height: 300, backgroundColor: 'red' });\r\n cont.addEventListener('postlayout', view_postlayout);\r\n \r\n // add container views to list\r\n pages.push(cont);\r\n } \r\n }\r\n else if (TEST_CASE == 2)\r\n {\r\n // CACHESIZE WORKS HERE: ONLY 3 IMAGES ARE LOADED\r\n \r\n // load imageviews directly (no container view)\r\n for (var i = 0; i < photos.length; i++)\r\n { \r\n // image\r\n var img = Ti.UI.createImageView({ id: i, image: photos[i], width: 200, height: 200 });\r\n img.addEventListener('load', img_load);\r\n \r\n // add imageview to list\r\n pages.push(img);\r\n } \r\n }\r\n else if (TEST_CASE == 3)\r\n {\r\n // CACHESIZE DOES NOT WORK HERE: ALL CONTAINERS AND CHILD REMOTE IMAGES ARE LOADED AT ONCE\r\n \r\n // load imageviews inside a container view\r\n for (var i = 0; i < photos.length; i++)\r\n { \r\n // image view\r\n var img = Ti.UI.createImageView({ id: i, image: photos[i], width: 200, height: 200 });\r\n img.addEventListener('load', img_load);\r\n \r\n // container view\r\n var cont = Ti.UI.createView({ id: 'container '+i, width: 300, height: 300, backgroundColor: 'blue' });\r\n cont.addEventListener('postlayout', view_postlayout);\r\n cont.add(img);\r\n \r\n // add container to list\r\n pages.push(cont);\r\n } \r\n }\r\n else if (TEST_CASE == 4)\r\n {\r\n // CACHESIZE DOES NOT WORK HERE: ALL CONTAINERS AND CHILD VIEWS ARE LOADED AT ONCE\r\n \r\n // load view inside a container view\r\n for (var i = 0; i < photos.length; i++)\r\n { \r\n // child view\r\n var child = Ti.UI.createView({ id: 'child '+i, width: 200, height: 200, backgroundColor: 'red' });\r\n child.addEventListener('postlayout', view_postlayout);\r\n \r\n // container view\r\n var cont = Ti.UI.createView({ id: 'container '+i, width: 300, height: 300, backgroundColor: 'blue' });\r\n cont.addEventListener('postlayout', view_postlayout);\r\n cont.add(child);\r\n \r\n // add container to list\r\n pages.push(cont);\r\n } \r\n }\r\n \r\n // bind pages to scrollable view\r\n pager.applyProperties({\r\n views: pages,\r\n currentPage: 0\r\n });\r\n \r\n \r\n}, 2000);\r\n{code}\r\n\r\nExpected result:\r\n\r\ncacheSize should work regardless if the pages are single controls or composite controls.", "attachment": [], "flagged": false, "summary": "IOS: ScrollableView: cacheSize property does not work when the view has a child view component", "creator": { "name": "sliang", "key": "sliang", "displayName": "Shuo Liang", "active": true, "timeZone": "Asia/Harbin" }, "subtasks": [], "reporter": { "name": "sliang", "key": "sliang", "displayName": "Shuo Liang", "active": true, "timeZone": "Asia/Harbin" }, "environment": "Ti SDK 3.2.3, iOS 7.1, Simulator 7.1\r\n", "comment": { "comments": [ { "id": "316341", "author": { "name": "bcproductions", "key": "bcproductions", "displayName": "Ed", "active": true, "timeZone": "America/Havana" }, "body": "will this be taken on for a fix on 3.3.1? it's a big issue for us that cacheSize is broken since we make extensive use of ScrollableViews on our app to browse content and images. thank you!", "updateAuthor": { "name": "bcproductions", "key": "bcproductions", "displayName": "Ed", "active": true, "timeZone": "America/Havana" }, "created": "2014-07-30T19:34:09.000+0000", "updated": "2014-07-30T19:34:09.000+0000" }, { "id": "321063", "author": { "name": "bcproductions", "key": "bcproductions", "displayName": "Ed", "active": true, "timeZone": "America/Havana" }, "body": "I'm still seeing this problem with the v3.4.0GA daily build, as well as v3.3.0. I've narrowed down the test and found the problem seems to be related to when the scrollableview pages are bound: \r\n\r\nIf they are bound before the scrollableview is added to the window, then cacheSize works. \r\n\r\nIf they are bound after the scrollableview has been added to the window, then cacheSize does not work. (This scenario is very common, since data can be pulled from a remote api and then bound to an already rendered scrollableview)\r\n\r\nHere's another test case to show this. Comment and uncomment the two lines below the two test conditions to see the difference. \r\n\r\nTest 1 binds the pages (views) before the scrollableview is added to the window and cacheSize works as expected as shown by the console log.\r\n\r\nTest 2 binds the pages after the scrollableview has been added to the window, and cacheSize is ignored. All thirteen pages are rendered with remote images downloaded when the pages are bound as can be seen by the log. The setTimeout() is there to make sure the pages are bound after the window .add() method, and to simulate pulling data from a remote api to build the pages.\r\n\r\nI hope this can be fixed in 3.4.0. This is the number one issue that will keep us from publishing, since we make use of scrollable views with _hundreds_ of pages that load remote data. Since cacheSize fails, all remote data is loaded at once, slowing the app, eating up lots of memory and making the app unstable (crashing).\r\n\r\n\r\n{code:title=app.js}\r\nvar win = Ti.UI.createWindow({ backgroundColor : 'white' });\r\n\r\n\r\nvar views = [],\r\n\tphotos = [\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/4/4c/Blackcat-Lilith.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Britishblue.jpg/640px-Britishblue.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/b/bd/Havana_Brown_-_choco.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Red_Cat_in_Torzhok_City.jpg/1280px-Red_Cat_in_Torzhok_City.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Cat_in_Kautokeino.jpg/1280px-Cat_in_Kautokeino.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/e/e7/Jammlich_crop.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Kamee01.jpg/800px-Kamee01.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Tabby_Pfaffengrund.JPG/1280px-Tabby_Pfaffengrund.JPG',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/2/20/Penny_snuggles.JPG',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/6/60/Neighbours_Siamese.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Catstalkprey.jpg/800px-Catstalkprey.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/2/28/Gato_Barra%C3%B1a_Galicia_2.jpg/1280px-Gato_Barra%C3%B1a_Galicia_2.jpg',\r\n\t\t'http://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Spielendes_K%C3%A4tzchen.JPG/800px-Spielendes_K%C3%A4tzchen.JPG'\r\n\t];\r\n \r\n\r\n// build pages for scrollable view \r\nfor (var i = 0; i < photos.length; i++)\r\n{\r\n\tvar \r\n\t\t// scrollview photo container\r\n\t\tsv = Ti.UI.createScrollView({\r\n\t\t\t top: 0\r\n\t\t\t,left: 0\r\n\t\t\t,right: 0\r\n\t\t\t,bottom: 0\r\n\t\t\t,showHorizontalScrollIndicator: false\r\n\t\t\t,showVerticalScrollIndicator: false\r\n\t\t}),\r\n\t\t\r\n\t\t// remote photo imageview\r\n\t\tp = Ti.UI.createImageView({\r\n\t\t\timage: photos[i],\r\n\t\t width: 300,\r\n\t\t height: Ti.UI.SIZE,\r\n\t\t\thires: true,\r\n\t\t\tautorotate: false\r\n\t\t});\r\n\t\r\n\t// remote photo events\r\n\tp.addEventListener('load', function(e) { Ti.API.info('Loaded: ' + e.source.image); });\r\n\tp.addEventListener('error', function(e) { Ti.API.info('Error:' + e.source.image); });\r\n\t\r\n\t// add\r\n\tsv.add(p);\r\n\r\n\t// add to collection\r\n\tviews.push(sv);\r\n}\r\n\r\n\r\n// scrollableview\r\nvar sbv = Ti.UI.createScrollableView({\r\n\ttop: 0,\r\n\tleft: 0,\r\n\tright: 0,\r\n\tbottom: 0,\r\n\tcacheSize: 3 // <-- ONLY PRE-LOAD 3 VIEWS (IMAGES)\r\n});\r\n\r\n\r\nTi.API.info('CHECK COUNT OF LOADED IMAGES BELOW...');\r\n\r\n\r\n/*\r\n * TEST 1: WORKS\r\n * BIND VIEWS BEFORE ADDING TO WINDOW.\r\n * RESPECTS CACHESIZE=3 AND PRE-LOADS ONLY 3 IMAGES\r\n */\r\n//sbv.applyProperties({ views: views, currentPage: 6 }); \r\n//win.add(sbv);\r\n\t\r\n\r\n\r\n/*\r\n * TEST 2: DOES NOT WORK!\r\n * BIND VIEWS AFTER ADDING TO WINDOW.\r\n * DOES NOT RESPECT CACHESIZE=3 AND LOADS ALL 13 IMAGES AT ONCE\r\n */\r\nwin.add(sbv); \r\nsetTimeout(function() { sbv.applyProperties({ views: views, currentPage: 6 }); }, 2000);\r\n\r\n\r\n\r\n// open window\r\nwin.open();\r\n{code}", "updateAuthor": { "name": "bcproductions", "key": "bcproductions", "displayName": "Ed", "active": true, "timeZone": "America/Havana" }, "created": "2014-08-29T17:19:59.000+0000", "updated": "2014-08-29T17:20:42.000+0000" }, { "id": "372620", "author": { "name": "nunocostapt", "key": "nunocostapt", "displayName": "Nuno Costa", "active": true, "timeZone": "Europe/Lisbon" }, "body": "Hey guys, Is this issue already fixed?\r\nThanks.", "updateAuthor": { "name": "nunocostapt", "key": "nunocostapt", "displayName": "Nuno Costa", "active": true, "timeZone": "Europe/Lisbon" }, "created": "2015-12-10T15:04:08.000+0000", "updated": "2015-12-10T15:04:08.000+0000" }, { "id": "377504", "author": { "name": "nicolomonili", "key": "nicolomonili", "displayName": "nicolomonili", "active": true, "timeZone": "Europe/Rome" }, "body": "Any news about this?", "updateAuthor": { "name": "nicolomonili", "key": "nicolomonili", "displayName": "nicolomonili", "active": true, "timeZone": "Europe/Rome" }, "created": "2016-02-22T09:45:38.000+0000", "updated": "2016-02-22T09:45:38.000+0000" }, { "id": "402328", "author": { "name": "a.marcone", "key": "a.marcone", "displayName": "Alberto Marcone", "active": true, "timeZone": "Europe/Berlin" }, "body": "same here, this bugs is breaking our application", "updateAuthor": { "name": "a.marcone", "key": "a.marcone", "displayName": "Alberto Marcone", "active": true, "timeZone": "Europe/Berlin" }, "created": "2016-12-01T10:55:10.000+0000", "updated": "2016-12-01T10:55:10.000+0000" }, { "id": "418941", "author": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "body": "Resolving ticket as Invalid as there is now a new version of Kitchen Sink available and we no longer support the version which relates to this ticket.", "updateAuthor": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2017-05-02T22:07:40.000+0000", "updated": "2017-05-02T22:07:40.000+0000" } ], "maxResults": 8, "total": 8, "startAt": 0 } } }