App randomly crashes with TableViews and semi-large built-in database

You must Login before you can answer or comment on any questions.

I can't find a pattern to this or why the app crashes. I used XCode to look for leaks and there really isn't anything of significance. The app goes through nested Windows that contain TableViews within a TabGroup. The database is fairly large - close to 1 MB. There are a lot of rows that are returned at times, but the app is consuming roughly under 2 MB of memory before it crashes. It does seem to take a while to crash it, but it's still a crash, and I don't like it. Sometimes instead of crashing, the TabGroup and the top bar disappears - and it's completely non-functional. The only way to make it work is to manually close the app and reopen it.

Here is what my code looks like from one of my Windows. I can't really post all the code, but it looks very much the same between Windows. Am I not following best practices? I can't figure this out, and I am new to Titanium.

(function(){
    // create var for the currentWindow
    var currentWin = Ti.UI.currentWindow;
 
    // get product category passed to Window
    var prodCat = Ti.UI.currentWindow.prodCat;
 
    // set the data from the database to the array
    function setData() {
 
        var db = Ti.Database.install('/db/ngpcertified.sqlite','ngpcertified');
 
        var query;
 
        // If product is dairy, make sure not to get alternative dairy products
 
        if (prodCat == 'Dairy') {
            query = "SELECT BrandName FROM ngpcertified WHERE Categories LIKE '%Dairy Products%' AND Categories NOT LIKE '%Alternative Dairy Products%' UNION SELECT BrandName FROM noupc WHERE Categories LIKE '%Dairy%' AND Categories NOT LIKE '%Alternative Dairy Products%'";
        } else {
            query = "SELECT DISTINCT BrandName FROM ngpcertified WHERE Categories LIKE '%"+ prodCat
                +"%' UNION SELECT DISTINCT BrandName FROM noupc WHERE Categories LIKE '%"+ prodCat +"%' ORDER BY BrandName";
        }
 
        var rows = db.execute(query);
 
        // create the array
        var dataArray = [];
 
        // Create a table row that takes user to All Products
        dataArray.push({title: 'All '+ prodCat +' Products', path:"/ui/common/product_all_category.js", font:{fontWeight:'bold', fontSize:16}, hasChild:true});
 
        while (rows.isValidRow())
        {
            dataArray.push({title:'' + rows.fieldByName('BrandName') + '', font:{fontWeight:'normal', fontSize:16}, hasChild:true, path:'/ui/common/product_list.js'});
            rows.next();    
        };
 
        rows.close();
        db.close();
 
        // set the array to the tableView
        tableview.setData(dataArray);
    };
 
    // create table view
    var tableview = Ti.UI.createTableView({});
 
    var win, prodName;
    tableview.addEventListener('click', function(e)
    {
        if (e.rowData.path)
        {
            win = Ti.UI.createWindow({
                url:e.rowData.path,
                title:e.rowData.title,
                backgroundColor:'white'
            });
 
            prodName = e.rowData.title;
            win.prodCat = Ti.UI.currentWindow.prodCat;
            win.prodName = prodName;
            Ti.UI.currentTab.open(win);
        }
    });
 
    currentWin.add(tableview);
    setData();
})();

— asked 8 months ago by Kyle Day
3 Comments
  • Have you tried adding className properties for your table rows? I've found Titanium apps to be quite unstable without them, especially in Android (I'm assuming you're talking about on the iPhone here).

    — commented 8 months ago by Chris Dunstall

  • Ok, I am reading about className. Do I define a font, etc on each row with a className? I am confused. Is there a way to define a class. Or does adding an identical className to each row automatically increase performance somehow?

    — commented 8 months ago by Kyle Day

  • Ok, I added className to all rows. Didn't make a difference. Still crashes. I figured out if I open and close enough TableViews in a certain order, the crash is kind of predictable. As if I reach a memory limit. But I don't has memory stays at ~2 MB. I restructured code so there is no SetData() function too. No difference.

    Any tips on how to make tables NOT crash on iPhone. If you don't have a lot of tables and data, I think it's likely you would never see this crash.

    If it's somewhat predictable after opening and closing Windows/Tables a certain amount of times, what could be going wrong if there is no memory issues?

    — commented 8 months ago by Kyle Day

3 Answers

Yes, iPhone. What would be the purpose of the className properties. I have to dive into documentation I guess. But will that require me to rewrite code?

you may want try this module if you think it's because of the large data set. It will give you paging ability. It was intended for web services but is also configurable to work with local data.

— answered 8 months ago by Alexander Bauer
answer permalink
1 Comment
  • Hi, thanks. This app is already going to cost me $100 for special web services, so there is no way I can put $20 a month on top of that.

    I think it's because of large data sets, but I'm experimenting with workarounds. Apple and most users may not catch or encounter this bug, but I still want it ironed out. Thanks.

    — commented 8 months ago by Kyle Day

I found an (ugly) solution/workaround. The app won't crash with the added events at the bottom. Only problem is I want to store the getCenter() point where the table left off before I destroyed it. My brain needs a break can't think of a solution right now, but I know there is one.

I was trying to create an empty view and pass with the BugFixView.getCenter(), but this is now getting really ugly. And I couldn't figure it out anyway.

Any help at saving a center point variable for each window is appreciated.

(function(){
    // create var for the currentWindow
    var currentWin = Ti.UI.currentWindow;
    var tableview;
 
    var populate = function() {
        // get product category passed to Window
        var prodCat = Ti.UI.currentWindow.prodCat;
 
        // create table view
        tableview = Ti.UI.createTableView({});
 
        var win, prodName;
        tableview.addEventListener('click', function(e)
        {
            if (e.rowData.path)
            {
                win = Ti.UI.createWindow({
                    url:e.rowData.path,
                    title:e.rowData.title,
                    backgroundColor:'white'
                });
 
                prodName = e.rowData.title;
                win.prodCat = Ti.UI.currentWindow.prodCat;
                win.prodName = prodName;
                Ti.UI.currentTab.open(win);
            }
        });
 
        currentWin.add(tableview);
 
        var db = Ti.Database.install('/db/ngpcertified.sqlite','ngpcertified');
 
        var query;
 
        // If product is dairy, make sure not to get alternative dairy products
 
        if (prodCat == 'Dairy') {
            query = "SELECT BrandName FROM ngpcertified WHERE Categories LIKE '%Dairy Products%' AND Categories NOT LIKE '%Alternative Dairy Products%' UNION SELECT BrandName FROM noupc WHERE Categories LIKE '%Dairy%' AND Categories NOT LIKE '%Alternative Dairy Products%'";
        } else {
            query = "SELECT DISTINCT BrandName FROM ngpcertified WHERE Categories LIKE '%"+ prodCat
                +"%' UNION SELECT DISTINCT BrandName FROM noupc WHERE Categories LIKE '%"+ prodCat +"%' ORDER BY BrandName";
        }
 
        var rows = db.execute(query);
 
        // create the array
        var dataArray = [];
 
        // Create a table row that takes user to All Products
        dataArray.push({title: 'All '+ prodCat +' Products', path:"/ui/common/product_all_category.js", font:{fontWeight:'bold', fontSize:16}, hasChild:true});
 
        while (rows.isValidRow())
        {
            dataArray.push({title:'' + rows.fieldByName('BrandName') + '', font:{fontWeight:'normal', fontSize:16}, className: 'products', hasChild:true, path:'/ui/common/product_list.js'});
            rows.next();    
        };
 
        rows.close();
        db.close();
 
        // set the array to the tableView
        tableview.setData(dataArray);
    }
 
    // remove and repopulate tables so app doesn't crash
    currentWin.addEventListener('blur', function(){
        currentWin.remove(tableview);
        tableview = null;
    });
    currentWin.addEventListener('focus', function(){
        populate();
    });
})();

— answered 8 months ago by Kyle Day
answer permalink
1 Comment
  • I forgot to mention, the problem the table is destroyed and recreated so it loses its center position. When the user goes back to the window, they are all the way at the top.

    It works, just a tad annoying since it's not the usual behavior of a table.

    — commented 8 months ago by Kyle Day

Your Answer

Think you can help? Login to answer this question!