0
Thumbsup

いい質問だ

0

Thumbsdown

うーん

tableviewのsingletapイベントでメモリリーク

19
19 0

投稿日:2015-06-13 11:32:04

いつもお世話になっております。

tableviewをタップするとその行にチェックマークをつけ、他の行のチェックマークはoffにするという処理をtableviewのsingletapイベントに記述しています。
見た目上は正しく動作しているのですが、instrumentsでメモリのチェックをした所、
タップされた回数分TiUITableViewRowProxyの#Livingが増え残ってしまっています。

表示されていたrow自体は、windowのcloseイベントでtableviewrowをremoveしnullをセットしているので、#Transientが行数分増え、問題なさそうです。
タップせずwindowを閉じる分にもメモリリークはおきません。
また、singletapをclickに変更するとメモリリークはおこりませんでした。

singletap内のコードをすべて消して実行しても#Livingがタップした回数分増えました。
clickに変更で問題は回避できるのですが、なぜsingletapで問題が起きるのか解せず気になっています。

clickに変更する以外の回避方法、またはこの現象の原因等、何かご存知の方がいらっしゃいましたら、お教え頂けますと嬉しいです。
いつも質問ばかりですみません<(_ _)> よろしくお願いいたします。

・Titanium SDKのバージョン 3.2.0
・iOS? Android? iOS
・iOSまたはAndroidのバージョン sdk7.0



回答

yagi_
yagi_
2540
Tcad_icon Tcmd_icon Tce_icon

Thumbsup

いい回答

0

Thumbsdown

うーん

eventListener内で参照しているオブジェクトがあったりするとGCされないので、コードがないとわからないかもしれないですね。

ちなみにeventListenerはTableViewオブジェクトにセットしていますか?Rowごとにセットするのはよろしくないとされています。

$.tableView.addEventListener('click', function(e){
  var row = e.row;//行のオブジェクトが渡される
});

yagi_様 ご回答ありがとうございます。 >ちなみにeventListenerはTableViewオブジェクトにセットしていますか? はい。TableViewオブジェクトにセットしています。 --- 19

19
19
0

Thumbsup

いい回答

0

Thumbsdown

うーん

yagi_様

ご回答ありがとうございました。


恥ずかしながらコードをさらしたいと思います。(//∇//)
少し削りましたが、メモリリークは再現できています。

app.js、win1.js、win2.jsの3つのファイルで構成。
app.jsからwin1を開き、win1からwin2を開きます。
win1、win2ともにTableViewをのせています。
win2のTableViewをタップ(singletap)してからwin2を閉じると、win1でrowを再セットする処理が走ります。(focus取得時)
想定では、この処理の終了後にメモリに残っているのは表示されているrowの分のみなのですが、win2でタップした回数分も残ってしまいます。
win2のtableviewのsingletapイベントをclickに変更すると、問題がでませんでした。???

ネットで検索しても同じような現象にあったというケースがでてこない為、singletap/clickイベント以前に何かコードの記述に問題があるのかもしれないです。
何かおかしい点やお気づきになった点がありましたら、ご指摘頂けますと嬉しいです。
よろしくお願いいたします。


/* 
 * test app.js
 */
(function() {

    Ti.App.MyFlg = false;

    var navWin = Ti.UI.iOS.createNavigationWindow({
        curWin : null, //*各winのfocusイベントでセットする
    });
    Ti.App.MyNav = navWin;

    var tmp = require('./ui/win1');
    var win1 = new tmp();
    navWin.window = win1;
    navWin.open();

})();

/*
 * test win1.js
 */
function win1() {
var blnOpened = false; //open時にtrue

    var self = Ti.UI.createWindow();
    var viewTbl = Ti.UI.createTableView();
    var btn = Ti.UI.createButton({title : 'next page', bottom : 50});
    self.add(viewTbl);
    self.add(btn);

    /* ウィンドウopen データ表示 */
    self.addEventListener('open',function(e){
        refresh();
        blnOpened = true;
    });

    /* ウィンドウfocusゲット テーブルをリフレッシュ */
    self.addEventListener('focus',function(e){
        Ti.App.MyNav.curWin = self; //グローバル変数にカレントウィンドウセット

        if (blnOpened == false) {
            if (Ti.App.MyFlg == true) {
                refresh();
            };
        };

        blnOpened = false;
    });

    /* 次画面を表示 */
    btn.addEventListener('click', function(e){ //
        var tmp = require('./ui/win2');
        var winNext = new tmp();
        Ti.App.MyNav.openWindow(winNext, { animated : true });
    }); 


    //// 以下、ローカル関数 ////
    /** 画面をリフレッシュ **/
    function refresh() {
        //テーブルセクションからオブジェクトをremove(*なくてもメモリから消える)
        // if (viewTbl.data.length > 0) {
            // removeRows();
        // };
        //テーブルdataをクリア 
        viewTbl.data  = null; 

        //テーブルのデータ
        var rs = [
            { id: 1, val1: '20150601', val2: 'あいうえお' },
            { id: 2, val1: '20150606', val2: 'かきくけこ' },
            { id: 3, val1: '20150611', val2: 'さしすせそ' },
        ];

        //行の高さ
        var intHeight = parseInt(Ti.App.Properties.getString('prop1'));

        //テーブルにデータをセット
        var tblSct = Ti.UI.createTableViewSection();
        for (var i = 0; i < rs.length; i++) {
            var row = Ti.UI.createTableViewRow();
            row.id = rs[i].id;
            row.title = rs[i].val1 + ' ' + rs[i].val2;
            row.height = intHeight;
            row.hasChild = true;
            tblSct.add(row); //セクションに追加
        };
        viewTbl.data = [ tblSct ]; //テーブルに追加
        Ti.App.MyFlg = false;
    };


    return self;
}
module.exports = win1;

/*
 * test win2.js
 */
function win2() {

    var self = Ti.UI.createWindow();
    var viewMain = Ti.UI.createView();
    var viewTbl = Ti.UI.createTableView();
    var tblSct = Ti.UI.createTableViewSection(); //*init()でセット
    viewMain.add(viewTbl);
    self.add(viewMain);

    /* ウィンドウopen データ表示 */
    self.addEventListener('open',function(e){ 
        init();
        check({ id : null }); 
    });

    /* ウィンドウfocusゲット グローバル変数にカレントウィンドウセット */
    self.addEventListener('focus',function(e){
        Ti.App.MyNav.curWin = self;
    });

    /* ウィンドウclose addしたオブジェクトを外す */
    self.addEventListener('close',function(e){
        removeAll();
    });

    /* テーブルtap tapされたrowにチェックを入れる */
    viewTbl.addEventListener('singletap',function(e){ //-----★ココをclickにするとOK
        if (typeof e.rowData == 'undefined') { 
        } else {
            check({ id : e.rowData.id });
            Ti.App.Properties.setString('prop1', e.rowData.id);         
        };
    });

    //// 以下、ローカル関数 ////
    /** テーブルにデータをセット **/
    function init() {
        var arr = [28,30,32,34,36];
        for (var i = 0; i < arr.length; i++){
            var val = arr[i];
            var row = Ti.UI.createTableViewRow();
            row.id = val;
            row.title = '' + val;       
            tblSct.add(row);
        };
        viewTbl.data = [ tblSct ];
        arr = null;
    };

    /** 指定行にチェックマーク表示 **/
    function check(_args) {
        var newVal = _args.id;
        var oldVal = parseInt(Ti.App.Properties.getString('prop1'));
        var blnUpd = true;
        if (newVal == null){ //起動時の場合
            newVal = oldVal;
            oldVal = null;                  
            blnUpd = false;
        };

        //viewTblのチェックを更新
        if (oldVal != newVal) {
            var rows = viewTbl.data[0].rows;
            for (var i = 0; i < rows.length; i++) {
                rows[i].hasCheck = ((rows[i].id == newVal) ? true : false);
            };

            //フラグを更新        
            if (blnUpd == true) {
                Ti.App.MyFlg = true;
            };
        };
    };

    /** ウィンドウからオブジェクトをremove **/
    function removeAll() {
        removeRows(); //テーブルセクションからrowをremove
        viewTbl.data = null;
        // viewTbl.removeEventListener('singletap', arguments.callee);
        // removeChildren(self); //childrenをremove
        Ti.App.MyNav.curWin = null; 
        self = null;
    };

    /** テーブルセクションからrowをremove **/
    function removeRows() {
        if (typeof tblSct.rows != 'undefined') {
            var len1 = tblSct.rows.length;
            for (var i = (len1 - 1); i >= 0; i--) {
                var row = tblSct.rows[i];
                // var len2 = row.children.length;
                // for (var j = (len2 - 1); j >= 0; j--) {
                    // var child = row.children[j];
                    // row.remove(child); //子objをremove
                    // child = null;
                // };
                tblSct.remove(row); //rowをremove
                row = null;
            };
            tblSct.rows = null;
        };
    };


    return self;
}
module.exports = win2;

以上


ログインすると回答することができます。