Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-13175] iOS: TableView setData() is broken on 3.0.2.GA

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2013-03-26T17:32:09.000+0000
Affected Version/sRelease 3.0.2
Fix Version/sRelease 3.1.0, 2013 Sprint 07 Core, 2013 Sprint 07
ComponentsiOS
Labels3.0.2, merge-3.0.3, qe-testadded, regression, setdata, tableview, triage
ReporterYgor Lemos
AssigneeMax Stepanov
Created2013-02-20T19:12:31.000+0000
Updated2013-10-01T08:52:05.000+0000

Description

I have always used setData() to dynamically change or empty tableViews (even the ones which are not on foreground at any given time). Ti 3.0.2.GA has broken this completely. First I always get the following error when I use setData() with no parameters or a empty list:
[INFO] :   PiniOn/1.1 (3.0.2.GA.5a77fe7)
[INFO] :   2013-02-20 16:06:11.101 PiniOn[29457:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:909
[INFO] :   2013-02-20 16:06:14.937 PiniOn[29457:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
Second, when I issue setData() it doesn't redraw the tableView automatically anymore. It seems I have to redraw the whole screen so the new data can get rendered every time. (like reopening the window which the tableView is on again after a setData). Looking at the source changes since 3.0.0 and the Assertion failure on TiUITableView.m it looks like it is something related to sections (which I don't use in this case). I have tested this in 2 big projects I'm working on (AirportChatter / PiniOn). All tableViews that uses setData dynamically are breaking with 3.0.2 on both projects.

Comments

  1. Ygor Lemos 2013-02-20

    This may be related too: https://github.com/appcelerator/titanium_mobile/commit/7c476f0695c0855da9b13fde034575bd59f0172e#iphone/Classes/TiUITableView.m It seems that the way tableView data was rendered severely changed.
  2. Ingo Muschenetz 2013-02-20

    One suggested workaround is to try:
       setData( [ ] ,{animated:true}).
       
    This forces a different code path. Does this help? Also, can you please add a sample piece of code?
  3. Eric Merriman 2013-02-20

    I tried this sample (modified from KS), I am not seeing an issue. Sample code would be super helpful.
       var win = Titanium.UI.createWindow();
       	
       	var data = [
       		{title:'Set uno'},
       		{title:'Set due'},
       		{title:'Set tre'},
       		{title:'Row4'},
       		{title:'Row5'},
       		{title:'Row6'},
       		{title:'Row7'},
       		{title:'Row8'},
       		{title:'Row9'},
       		{title:'Row10'},
       		{title:'Row11'},
       		{title:'Row12'},
       		{title:'Row13'},
       		{title:'Row14'},
       		{title:'Row15'}	
       	];
       	var tableView = Titanium.UI.createTableView({data:data});
       
       	
       	button1 = Ti.UI.createButton({
       		title: 'Empty',
       		width:80,
       		height: 40,
       		left:0,
       		bottom:0
       	});
       	
       	button1.addEventListener('click', function(){
       		data = [];
       		tableView.setData(data);
       	});
       	
       		button2 = Ti.UI.createButton({
       		title: 'Full',
       		width:80,
       		height: 40,
       		right:0,
       		bottom:0
       	});
       	
       	button2.addEventListener('click', function(){
       		data = [{title:'Set One'},
       		{title:'Set two'},
       		{title:'Set three'},
       		{title:'Row4'},
       		{title:'Row5'},
       		{title:'Row6'},
       		{title:'Row7'},
       		{title:'Row8'},
       		{title:'Row9'},
       		{title:'Row10'},
       		{title:'Row11'},
       		{title:'Row12'},
       		{title:'Row13'},
       		{title:'Row14'},
       		{title:'Row15'}	];
       		tableView.setData(data);
       	});
       	
       	win.add(tableView);
       	win.add(button1);
       	win.add(button2);
       	win.open();
       
  4. Ygor Lemos 2013-02-20

    Hi Eric, I don't have a simple test case except from the actual source of two already published apps... I can try to make a TC here. I think that the main reason that you're not experiencing the problem with this testcase is because you're never changing from the main window nor drilling down to another window where the tableview should be... also in my apps I use the setData() with Ti.UI.TableViewRow objects not with simple dictionaries containing the title... this may lead to another code path... anyways... will try to reproduce in a general test case... but I guess other devs will have the same problem soon...
  5. Eric Merriman 2013-02-21

    Thanks Ygor, let me try setting the rows and adding some windows.
  6. Martin Guillon 2013-02-21

    @Ygor: great apps! you did everything in Ti? even the graphs in PiniOn? About your assertion problem. I fixed this in my private branch. I cant really make a pull request as i rewrote a lot too much in tableviews :s The problem is that numberOfRowsInSection can be called while modifying sections. What i did is use a boolean "settingData" that i set to true while replacing the tableview section data. If settingData is true then numberOfRowsInSection return 0. That should fix the assertion failure
  7. Ygor Lemos 2013-02-21

    Hi Martin, Yes, both are made 100% with Titanium :) Cool, do you have the intention of promoting this fix up to the main tree? As of now I don't realy need to go to Ti 3.0.2.GA but I'm worried with the future... I think others with complex TableViews (pre-cached by events for a smoother UI/UX) may suffer with this too...
  8. Ingo Muschenetz 2013-02-21

    @Ygor and @Martin. If there is a regression we will be addressing it. But we do not yet have a good test case that demonstrates the problem.
  9. Federico Casali 2013-02-22

    Tried with another sample code (using tableViewRows too) but was not able to reproduce. APP.JS file
       // app.js
       
       var openWin2 = require('win2')
       
       var data = [];
       
       function createData(e) {
       
       		if (!data){
       			data = []
       		};
       
       		for (var i = 0; i < 6; i++) {
       			var tvr = Ti.UI.createTableViewRow({
       				title : 'row ' + i,
       				hasChild : true,
       				customProperty : e,
       				backgroundColor : 'yellow',
       				leftImage : 'snoopy.png'
       			});
       
       			tvr.addEventListener('click', function(e) {
       				tvr.customProperty.text = 'test_Changed';
       				e.row.backgroundColor = 'blue';
       				e.row.leftImage=null;
       				alert(JSON.stringify('Changed the properties of ' + e.row.title));
       			});
       			data.push(tvr);
       		}
       		Ti.API.info('data[] array of tableViewRows created: ' + JSON.stringify(tvr));
       	};
       
       var win1 = Ti.UI.createWindow({
       	title : 'test',
       	backgroundColor : 'gray'
       });
       
       win1.addEventListener('open', function(){
       	createData('default');
       	Ti.API.info(JSON.stringify(data));
       })
       
       var button = Ti.UI.createButton({
       	title:'Open Win',
       	top:20
       });
       button.addEventListener('click', function() {
       	
       	var win2 = new openWin2();
       	win2.open();
       
       });
       
       win1.add(button);
       
       win1.open();
       
       
    WIN2.JS file
       // win2.js
       
       function openWin2() {
       	var win2 = Titanium.UI.createWindow({
       		backgroundColor:'gray',
       		title:'win2'
       	});
       
       	win2.addEventListener('open', function(){
       		alert('click the rows to change TableViewRows values')
       	});
       	
       	var view = Ti.UI.createView({
       		top:0,
       		backgroundColor:'black'
       	});
       	var label = Ti.UI.createLabel({
       		text:'Back',
       		color:'white',
       		font:{
       			fontSize:'20dp'
       		},
       		top:5
       	});
       	view.add(label);
       	
       	view.addEventListener('click', function(){
       		win2.close()
       	});
       	win2.add(view);
       
       
       	var tableView = Titanium.UI.createTableView({
       		data:data,
       		top: 40,
       		bottom:50
       	});
       
       	button1 = Ti.UI.createButton({
       		title : 'Empty',
       		width : 80,
       		height : 40,
       		left : 0,
       		bottom : 0
       	});
       
       	button1.addEventListener('click', function() {
       		data = [];
       		tableView.setData(data);
       		data = null;
       	});
       
       	button2 = Ti.UI.createButton({
       		title : 'Reset',
       		width : 80,
       		height : 40,
       		right : 0,
       		bottom : 0
       	});
       
       	button2.addEventListener('click', function() {
       		data = null;
       		createData({
       			text : 'test',
       			customString : 'testCustomString',
       			customNumber : 42
       		});
       		tableView.setData(data, {
       			animated : true
       		});
       	});
       
       	button3 = Ti.UI.createButton({
       		title : 'Add',
       		width : 80,
       		height : 40,
       		right: 100,
       		bottom : 0
       	});
       
       	button3.addEventListener('click', function() {
       		createData({
       			text : 'test',
       			customString : 'testCustomString',
       			customNumber : 79
       		});
       		tableView.setData(data, {
       			animated : false
       		});
       	});
       
       	win2.add(tableView);
       	win2.add(button1);
       	win2.add(button2);
       	win2.add(button3);
       	
       	return win2;
       };
       
       module.exports = openWin2;
       
       
  10. Martin Guillon 2013-02-23

    @Federico: first i am sorry as i wont have the time to investigate it. But to me the problem has nothing to do with windows or something else, but more about the "duration" of the setData. AS Ingo said a simple solution to that problem is a setData([]). To me if you want to reproduce it, create a tableview with something like 300 rows, custom rows, where the setData computation would be long enough for a "numberOfRowsInSection" to be called while setting Data. That my take on this.
  11. Ygor Lemos 2013-03-05

    Can I give access to an appcelerator engineer on my private github project so he can see the codepath causing this error?
  12. Ingo Muschenetz 2013-03-06

    Ygor, sure. Try https://github.com/eric34 for now.
  13. Ygor Lemos 2013-03-08

    just added eric34 to my ios project so he can pull the code and read the flow... let me know if you need a walkthrough on the app flow... also, if you need more people to access it... just beware that this is production code... thanks!
  14. Ygor Lemos 2013-03-23

    any news on this one? Kinda worried on not being able to move forward on Ti versions due to this...
  15. Eric Merriman 2013-03-25

    @Ygor, Hello. I'll be working on this tomorrow morning. I'll report back.
  16. Eric Merriman 2013-03-25

    Hello all, The cause of this has been discovered and dev is creating a pull request. My examples had no search feature. New sample code being created and will be incorporated in future test runs. Meu português está melhorando.
  17. Max Stepanov 2013-03-25

    Reproducible test case:
        var win = Titanium.UI.createWindow();
        
        var data = [
        {title:'Set uno'},
        {title:'Set due'},
        {title:'Set tre'},
        {title:'Row4'},
        {title:'Row5'},
        {title:'Row6'},
        {title:'Row7'},
        {title:'Row8'},
        {title:'Row9'},
        {title:'Row10'},
        {title:'Row11'},
        {title:'Row12'},
        {title:'Row13'},
        {title:'Row14'},
        {title:'Row15'} 
        ];
        var search = Titanium.UI.createSearchBar({
        	barColor:'#000', 
        	showCancel:true,
        	height:43,
        	top:0,
        });
        var tableView = Titanium.UI.createTableView({
        	data:data,
        	search: search,
        	searchHidden: true,
        	hideSearchOnSelection:true,
        });
        
        
        button1 = Ti.UI.createButton({
        	title: 'Empty',
        	width:80,
        	height: 40,
        	left:0,
        	bottom:0
        });
        
        button1.addEventListener('click', function(){
        	data = [];
        	tableView.setData(data);
        });
        
        button2 = Ti.UI.createButton({
        	title: 'Full',
        	width:80,
        	height: 40,
        	right:0,
        	bottom:0
        });
        
        button2.addEventListener('click', function(){
        	data = [{title:'Set One'},
        	{title:'Set two'},
        	{title:'Set three'},
        	{title:'Row4'},
        	{title:'Row5'},
        	{title:'Row6'},
        	{title:'Row7'},
        	{title:'Row8'},
        	{title:'Row9'},
        	{title:'Row10'},
        	{title:'Row11'},
        	{title:'Row12'},
        	{title:'Row13'},
        	{title:'Row14'},
        	{title:'Row15'} ];
        	tableView.setData(data);
        });
        
        win.add(tableView);
        win.add(button1);
        win.add(button2);
        win.open();
        
  18. Max Stepanov 2013-03-25

    PR https://github.com/appcelerator/titanium_mobile/pull/4029
  19. Ygor Lemos 2013-03-28

    @Eric Hey Eric and Max, thank you very much for solving this!!! Eric, Nice that we could also improve your Portuguese in the process :) Thanks!
  20. Shyam Bhadauria 2013-04-06

    Its working as per the test case given by Max. Environment used for verification - Titanium SDK: 3.1.0.v20130405170202 Titanium  Studio:3.1.0.201304011603 Device : iPhone iOS 6.0, ipad4 iOS 6.0

JSON Source