这是一个bug。得改。

先传两段代码:
[size=7][color=#FF0000]TestView.lua[/color][/size]
<pre class="brush:lua; toolbar: true; auto-links: false;">–[[
测试界面
]]–
local TestView = class("TestView", function()
    local node = display.newNode();
    node:setTouchEnabled(false);
    return node;
end)

–构造方法
function TestView:ctor(type)
    local sp1 = display.newSprite("p1.png");
    self:addChild(sp1);
end

return TestView;
</pre>

[size=7][color=#FF0000]MyApp.lua[/color][/size]
<pre class="brush:lua; toolbar: true; auto-links: false;">
require("config")
require("framework.init")
local TestView = import("app.test.TestView")
local MyApp = class("MyApp", cc.mvc.AppBase)
function MyApp:ctor()
    MyApp.super.ctor(self)
end

function MyApp:run()
    cc.FileUtils:getInstance():addSearchPath("res/")
    self:enterScene("MainScene")
    _G.testView = TestView.new();
end

return MyApp
</pre>

[size=7][color=#FF0000]MainScene.lua[/color][/size]
<pre class="brush:lua; toolbar: true; auto-links: false;">
local TestView = import("…test.TestView")
local MainScene = class("MainScene", function()
    return display.newScene("MainScene")
end)

function MainScene:ctor()
    local btn =  cc.ui.UIPushButton.new({});
    local lbl = cc.ui.UILabel.new({text = "测试一下",font = "Arial",size = 42, color = cc.c3b(15, 197, 92),align = cc.TEXT_ALIGNMENT_CENTER});
    btn:setButtonLabel("normal", lbl);
    btn:onButtonClicked(function()
        self:addChild(_G.testView);
        _G.testView:pos(display.cx,display.cy+200);
    end);
    btn:pos(display.cx,display.cy);
    self:addChild(btn);
end

return MainScene
</pre>

我的想法:本来想的是点击测试一下按钮。然后会在测试按钮上面显示一个TestView(里面就是一个p1.png)。。
得到的结果: 控制台报错。报错内容如下:
[color=#FF0000]

LUA ERROR: ASSERT FAILED ON LUA EXECUTE: Argument must be non-nil

stack traceback:
    [C]: in function 'addChild'
    [string ".\app/scenes/MainScene.lua"]:11: in function <[string ".\app/scenes/MainScene.lua"]:10>
    [string ".\framework/cc/components/behavior/EventProtocol.lua"]:58: in function 'dispatchEvent'
    [string ".\framework/cc/ui/UIPushButton.lua"]:116: in function <[string ".\framework/cc/ui/UIPushButton.lua"]:85>
----------------------------------------[/color]

从上面的报错可以看出说我的testView是空。问题是不可能啊。因为我的testView实在MyApp.lua里面用[color=#FF0000]_G[/color] 来保存的。[color=#FF0000]全局的啊。。[/color] 百思不得其解。。

这个时候我不小心把TestView的   node:setTouchEnabled(false); 设置成了  node:setTouchEnabled([color=#FF0000]true[/color]); 。尼玛发现居然不报错。。

这个时候我去看了一下c++ node 的setTouchEnabled方法。代码如下:

<pre class="brush:cpp; toolbar: true; auto-links: false;">if (enabled)
            {
                registerWithTouchDispatcher();
            }
            else
            {
                unregisterWithTouchDispatcher();
            }</pre>

。,继续进入registerWithTouchDispatcher这个方法。会发现这样的东西。

<pre class="brush:cpp; toolbar: true; auto-links: false;">//    CCLOG("CCNODE: REGISTER WITH TOUCH DISPATHCER <%p>", this);
    ScriptEventCenter *scriptEventCenter = Director::getInstance()->getScriptEventCenter();
    if (scriptEventCenter)
    {
        scriptEventCenter->addTouchableNode(this);
    }</pre>

再深入可以看出:C++把所有touch的node(或者sprite等等)引用放到他的一个ScriptEventCenter对象里面。 那么问题来了。

我的问题:
[list=1][li]为什么lua的_G没有保存testView的引用呢?[/li][li]为什么C++有对其进行保存应用就可以呢?[/li][/list]

大家来讨论一下哈。

在cocos中,C++对象由lua来管理其生命周期是不合理的。因为cocos的C++对象如Node等,在C++里都是autorelease的,用户只需要专注于对象的使用过程,当对象从界面上移除就会自动得到释放。如果当Lua持有C++对象时保留一个引用,用户必须自己时刻注意在不使用C++对象时将引用变量置为nil,这样会有很多工作量,并且更容易由于用户的不小心而产生内存泄漏。
另外一个问题是,lua的GC是在lua vm占用的内存达到一定程度时才会释放,而C++对象的内存占用并不会计算在里面,如果由Lua来管理其生命周期,有可能产生内存已经使用很多,但仍然无法激发GC的情况,造成内存峰值过大,为避免这一点,必须定时强制lua进行GC,这样又不可避免的对运行效率造成影响,出现明显的卡顿。
实际上,针对这个问题论坛曾经有过一个投票,对大家是否支持修改成由lua管理C++对象的生命周期进行调查,结果完全没有悬念的几乎全员反对。因为只要是对lua开发稍为熟悉一些的开发者,都会了解这一功能是画蛇添足的。

setTouchEnabled()对sprite的引用,会因为removeChild(sprite)而将sprite内存回收吗?
还是说。。。泄漏了?

这是个问题。我也想知道。

会回收的,PS:为什么小于10个字不能回复?