{ "id": "81112", "key": "TIMOB-5429", "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": [ { "id": "13502", "description": "Sprint 2012-14 Core", "name": "Sprint 2012-14 Core", "archived": true, "released": true, "releaseDate": "2012-07-15" }, { "id": "13505", "description": "Release 3.0.0", "name": "Release 3.0.0", "archived": true, "released": true, "releaseDate": "2012-12-14" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2012-07-18T19:35:20.000+0000", "created": "2011-10-04T14:56:26.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "module_tableviewrow", "qe-testadded" ], "versions": [ { "id": "11570", "description": "", "name": "Release 1.7.2", "archived": true, "released": true, "releaseDate": "2011-07-21" } ], "issuelinks": [ { "id": "18373", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "93100", "key": "TIMOB-9500", "fields": { "summary": "iOS: Table view rows that are not visible on screen should be recycled", "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" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2013-10-07T09:57:05.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": "While profiling our app I noticed that scrolling through the stream continues to generate new views rather than reusing existing ones. These rows do in fact have classNames set, and when the table is cleared, all the views are indeed garbage collected, so I do not believe it is an issue of external references being kept. Also of interest, the # of transitory instances also continues to rise, suggesting that the rows are being continuously garbage collected and recreated (potentially as a result of continuous setData calls).\r\n\r\nVideo of the issue: http://cl.ly/1M3L2T2y2k3k1q1y3g2Y\r\nFactory method used to generate these rows: https://gist.github.com/7bd7d37b056562eb9962\r\n\r\nNot that to page in new rows, they are added to the main tableViewSection, and then setData is called on the table with the entire array of sections again\r\n", "attachment": [], "flagged": false, "summary": "iOS: TableViewRows are not being reused even though className is set", "creator": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "environment": "Ti 1.7.2", "comment": { "comments": [ { "id": "167949", "author": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "body": "To create similar results:\r\n\r\n{code}\r\nvar win = Ti.UI.createWindow();\r\n\r\nfunction createRow(c) {\r\n\t\tvar row = Ti.UI.createTableViewRow();\r\n\trow.selectedBackgroundColor = '#fff';\r\n\trow.height = 100;\r\n\trow.className = 'datarow';\r\n\trow.clickName = 'row';\r\n\r\n\tvar photo = Ti.UI.createView({\r\n\t\tbackgroundImage:'user.png',\r\n\t\ttop:5,\r\n\t\tleft:10,\r\n\t\twidth:50,\r\n\t\theight:50,\r\n\t\tclickName:'photo'\r\n\t});\r\n\trow.add(photo);\r\n\r\n\r\n\tvar user = Ti.UI.createLabel({\r\n\t\tcolor:'#576996',\r\n\t\tfont:{fontSize:16,fontWeight:'bold', fontFamily:'Arial'},\r\n\t\tleft:70,\r\n\t\ttop:2,\r\n\t\theight:30,\r\n\t\twidth:200,\r\n\t\tclickName:'user',\r\n\t\ttext:'Fred Smith '+c\r\n\t});\r\n\r\n\trow.filter = user.text;\r\n\trow.add(user);\r\n\r\n\tvar fontSize = 16;\r\n\tif (Titanium.Platform.name == 'android') {\r\n\t\tfontSize = 14;\r\n\t}\r\n\tvar comment = Ti.UI.createLabel({\r\n\t\tcolor:'#222',\r\n\t\tfont:{fontSize:fontSize,fontWeight:'normal', fontFamily:'Arial'},\r\n\t\tleft:70,\r\n\t\ttop:21,\r\n\t\theight:50,\r\n\t\twidth:200,\r\n\t\tclickName:'comment',\r\n\t\ttext:'Got some fresh fruit, conducted some business, took a nap'\r\n\t});\r\n\trow.add(comment);\r\n\r\n\tvar calendar = Ti.UI.createView({\r\n\t\tbackgroundImage:'/KS_nav_ui.png',\r\n\t\tbottom:2,\r\n\t\tleft:70,\r\n\t\twidth:32,\r\n\t\tclickName:'calendar',\r\n\t\theight:32\r\n\t});\r\n\trow.add(calendar);\r\n\r\n\tvar button = Ti.UI.createView({\r\n\t\tbackgroundImage:'KS_nav_views.png',\r\n\t\ttop:35,\r\n\t\tright:5,\r\n\t\twidth:36,\r\n\t\tclickName:'button',\r\n\t\theight:34\r\n\t});\r\n\trow.add(button);\r\n\r\n\tvar date = Ti.UI.createLabel({\r\n\t\tcolor:'#999',\r\n\t\tfont:{fontSize:13,fontWeight:'normal', fontFamily:'Arial'},\r\n\t\tleft:105,\r\n\t\tbottom:5,\r\n\t\theight:20,\r\n\t\twidth:100,\r\n\t\tclickName:'date',\r\n\t\ttext:'posted on 3/11'\r\n\t});\r\n\trow.add(date);\r\n\treturn row;\r\n}\r\n\r\nvar data = [];\r\nvar lastRow = 10;\r\nfor (var c=0;c= nearEnd))\r\n\t\t{\r\n\t\t\tbeginUpdate();\r\n\t\t}\r\n\t}\r\n\tlastDistance = distance;\r\n});\r\n\r\n\r\nwin.open();\r\n{code}", "updateAuthor": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-04T14:57:03.000+0000", "updated": "2011-10-04T14:57:03.000+0000" }, { "id": "167951", "author": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "updateAuthor": { "name": "adecena", "key": "adecena", "displayName": "Anthony Decena", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-04T14:59:03.000+0000", "updated": "2011-10-04T14:59:03.000+0000" }, { "id": "167955", "author": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Note that in the app in the original video, paging is being done through setData instead of appendRow", "updateAuthor": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-04T15:22:08.000+0000", "updated": "2011-10-04T15:22:08.000+0000" }, { "id": "167957", "author": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "body": "setData must start with a fresh set of classNames and views. Also why wasn't the TC-269 just moved to this ticket? Most of the required fields don't have appropriate information in them.", "updateAuthor": { "name": "dthorp", "key": "dthorp", "displayName": "Don Thorp", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-04T15:27:44.000+0000", "updated": "2011-10-04T15:27:44.000+0000" }, { "id": "167963", "author": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "body": "re: \"setData must start with a fresh set of classNames and views\". Are you saying that setData can not reliably be used for paging? Appending rows one at a time is extremely slow.", "updateAuthor": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-04T15:52:47.000+0000", "updated": "2011-10-04T15:52:47.000+0000" }, { "id": "168845", "author": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Has any progress been made on this? Anything else I can provide that would help?", "updateAuthor": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-11T10:43:44.000+0000", "updated": "2011-10-11T10:43:44.000+0000" }, { "id": "184561", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "The biggest issue is going to be that even with reusing className, there will be major performance degradation when setting any properties which affect layout (the exact thing that className is supposed to prevent) and so we will need to filter those properties which affect layout extensively and impose strict rules on what constitutes two rows with the same className.", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-02-28T16:50:16.000+0000", "updated": "2012-02-28T16:50:16.000+0000" }, { "id": "184563", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "The following tickets must all be checked for possible regressions when resolving this issue (both for tables using className and those without, where appropriate):\r\n\r\nTIMOB-5380\r\nTIMOB-5441\r\nTIMOB-6134\r\nTIMOB-3600\r\nTIMOB-4687\r\nTIMOB-3007\r\nTIMOB-2225\r\nTIMOB-1037\r\nTIMOB-2346\r\nTIMOB-2304\r\nTIMOB-5279\r\nTIMOB-6082\r\nTIMOB-1664", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-02-28T16:59:28.000+0000", "updated": "2012-02-28T17:05:21.000+0000" }, { "id": "184949", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "This bug may need to be marked INVAID. From Apple's documentation:\r\n\r\nbq. The table view'€™s delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell. If the cell object does not have an associated reuse identifier, this method is not called. If you override this method, you must be sure to invoke the superclass implementation.\r\n\r\nThis indicates that any subviews need to be re-added because they may be cleaned up by the system (they are no longer drawn, and therefore are fair game for removal). In this case there is absolutely no performance improvement from className.", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-03-02T15:59:35.000+0000", "updated": "2012-03-02T15:59:35.000+0000" }, { "id": "185010", "author": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "body": "The point of the reuse identifiers is precisely so that the expensive operation of creating views does not need to occur for each row. I believe the word \"reset\" here just means that all subviews must be returned to a blank state, for example UILabels must have their text cleared. If you take a look at how any open source iOS app is built, you will see this is the case.", "updateAuthor": { "name": "getglue", "key": "getglue", "displayName": "GetGlue", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-03-05T08:29:46.000+0000", "updated": "2012-03-05T08:29:46.000+0000" }, { "id": "185122", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "There is an apparent bug in iOS 5 preventing this fix. Apparently subviews of a cell now track the row index in some manner, since hit detection on them sends the wrong row index to the table after a row has been reproxied. As a result this fix may be delayed.", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-03-05T20:54:37.000+0000", "updated": "2012-03-05T21:59:59.000+0000" }, { "id": "208422", "author": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Pull merged.", "updateAuthor": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-07-18T19:35:20.000+0000", "updated": "2012-07-18T19:35:20.000+0000" }, { "id": "208424", "author": { "name": "iotashan", "key": "iotashan", "displayName": "Shannon Hicks", "active": true, "timeZone": "America/Chicago" }, "body": "GetGlue : I'd love to hear results of you re-testing with a fresh CI build!", "updateAuthor": { "name": "iotashan", "key": "iotashan", "displayName": "Shannon Hicks", "active": true, "timeZone": "America/Chicago" }, "created": "2012-07-18T19:51:10.000+0000", "updated": "2012-07-18T19:51:10.000+0000" }, { "id": "215023", "author": { "name": "oromero", "key": "oromero", "displayName": "Olga Romero", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified fix with:\r\nTitanium Studio, build: 2.1.1.201207271312\r\nTitanium SDK: 2.2.0.v20120816212512\r\nDevices:\r\niPhone 4s 5.0.1\r\niPad1 ios5 5.1.1\r\nSimulator 5.1\r\nMac osx 10.8 Mountain Lion", "updateAuthor": { "name": "oromero", "key": "oromero", "displayName": "Olga Romero", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-08-17T15:57:45.000+0000", "updated": "2012-08-17T15:57:45.000+0000" } ], "maxResults": 23, "total": 23, "startAt": 0 } } }