Trouble with Composer and removing native objects

I apologize upfront for the long code. I am simply clueless as to how to handle the issue.

First, the code compiles for the xcode simulator and works. However, I am getting an error in the Corona Simulator. 

The only way I can figure to get rid of all the scene objects and still have everything work, is to move my enterButton to the Show() function and use a forward reference. 

Here is my error (again it doesn’t interfere with the code working:

capture.lua:147: attempt to index upvalue ‘enterButton’ (a nil value)

message

stack traceback:

?: in function <?:218>

Here is the code:

local composer = require( “composer” )

[lua]-- Forward References

local username

local enterButton

local gotoMain

– create and open SQL Database

local path = system.pathForFile(“data.db”, system.DocumentsDirectory)

local db = sqlite3.open(path)

local tablesetup = [[CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY autoincrement, capture);]]

db:exec( tablesetup )

– Don’t forget to close the DataBase at some point. Not in the Capture Module though.

local widget = require(“widget”)

local scene = composer.newScene()

function scene:create( event )

    local sceneGroup = self.view

    

    local background = display.newRect( display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight )

    background:setFillColor(255,255,255)

    

    

    local capturetitle = display.newText(“Capture Page”, 0, 40, native.systemFont, 80)

    capturetitle:setFillColor(0,0,0)

    capturetitle.x = _W * 0.5

    capturetitle.y = 80

    

    gotoMain = display.newText(“Return to Main Page”, 0, 40, native.systemFont, 80)

    gotoMain:setFillColor(0,0,0)

    gotoMain.x = _W * 0.5

    gotoMain.y = _H - 80

    

    function gotoMain:touch(e)

        if(e.phase == “began”) then

            

            --“scene:hide()”

            --print(“Began  under gotoMain”)

            composer.gotoScene( “scenet” )

            

        end

        

        return true

    end

    

    

    background:addEventListener(“tap”, background)

    – Return to Main menu text button

    gotoMain:addEventListener(“touch”, gotoMain)

    

    – Hide keyboard upon tapping the background

    function background:tap(e)

        native.setKeyboardFocus(nil)

    end

    

    --sceneGroup:insert(  )     

    

    sceneGroup:insert( background )

    sceneGroup:insert( capturetitle )

    --sceneGroup:insert( enterButton )

    sceneGroup:insert( gotoMain )

    --sceneGroup:insert( username )

    

end

– “scene:show()”

function scene:show( event )

    

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        – Called when the scene is still off screen (but is about to come on screen).

    elseif ( phase == “did” ) then

        – Called when the scene is now on screen.

        – Insert code here to make the scene come alive.

        – Example: start timers, begin animation, play audio, etc.

        

        – Create, Position and instantiate Input Textfield

        username = native.newTextField(0,0, _W * 0.8, 100)

        local font = “HelveticaNeue” or system.nativeFont

        local hintText = “Enter an item to capture”

        username.inputType = “default”

        username.font = native.newFont(font,24)

        username.text = hintText

        username.align = “center”   

        username.x = _W * 0.5

        username.y = _H * 0.2

        

        enterButton = widget.newButton{

            id = “enter button”,

            onRelease = buttonTapped,

            defaultFile = “images/buttontest.png”,

        overFile = “images/buttontest_touch.png”}

        enterButton.x = _W * 0.5

        enterButton.y = _H * 0.4

        

        – Input Textfield function

        function username:userInput(e)

            if(e.phase == “began”) then

                e.target.text = “”

                --print("Began " … e.target.text)

                

            elseif(e.phase == “editing”) then

                --print("Editing " … e.target.text)

                

            elseif(e.phase == “ended”) then – ended happens when the enterButton is touched

                --print("Ended " … e.target.text)

                

                local text = username.text

                print(“tapped Enter Button :” … text)

                local sql = [[INSERT INTO test VALUES(NULL, ‘]] … text … [[’);]]

                db:exec(sql)

                

                --print(“tapped Enter Button :” … username.text)

                

                e.target.text = “You may enter another Event”

                

            elseif(e.phase == “submitted”) then

                print("Submitted " … e.target.text)

                

                local sql = [[INSERT INTO test VALUES(NULL, ‘]] … username.text … [[’);]]

                db:exec(sql)

                

                e.target.text = “” – This is empty because we don’t re-enter the began phase to clear the textfield

                

            end

        end

        username:addEventListener(“userInput”, username)

        – listener for textfield

        enterButton:addEventListener(“tap”, enterButton)

        – blur the keyboard on background touch

    end

end

function scene:hide( event )        

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        

        – Called when the scene is on screen (but is about to go off screen).

        – Insert code here to “pause” the scene.

        – Example: stop timers, stop animation, stop audio, etc.

        

                enterButton:removeSelf()  

                username:removeSelf()

        composer.removeScene( “capture”, false )

        

        

    elseif ( phase == “did” ) then

        – Called immediately after scene goes off screen.

    end

end

function scene:destroy( event )

    local sceneGroup = self.view

    

end

scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )

return scene[/lua]

You can certainly forward declare enterButton like you have, but you can also define it in the create() function.  The step you are missing is you are not adding enterButton to your scene’s view group:

sceneGroup:insert(enterButton)

If you do this step, you can create it in scene:create() and all will be right with the world.  When the scene goes away, the button will go with it.  Then you don’t need to explicitly remove it in scene:exit().

Composer works by managing the display objects ( not native ones ) that you insert into the scene’s group.  It will delete the items, transition them on and off the screen as needed.

Rob

Rob,

Thanks for the suggestion.  I had originally build my scene with all display objects in the scene:create() and with adding SQL functionality I started moving things around to make it work. But I have started over and run into the same issue. Below is the new code. I just built it up until I ran into the issue and it didn’t show up until I added the removeSelf() (widget) to the scene:hide().

I guess my issue is with how to I get rid of Native objects from the scene.

complete.lua:116: attempt to index upvalue ‘username’ (a nil value)

message

Thanks for your help in advance. .  .

[lua]

local composer = require( “composer” )

local scene = composer.newScene()


– All code outside of the listener functions will only be executed ONCE

– unless “composer.removeScene()” is called.


– local forward references should go here

local widget = require(“widget”)

local username

local gotoMain


– “scene:create()”

function scene:create( event )

    

    local sceneGroup = self.view

    

    – Initialize the scene here.

    – Example: add display objects to “sceneGroup”, add touch listeners, etc.

    local background = display.newRect( display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight )

    background:setFillColor(255,255,255)

    

    – MAIN TITLE TEXT

    local capturetitle = display.newText(“Capture Page”, 0, 40, native.systemFont, 80)

    capturetitle:setFillColor(0,0,0)

    capturetitle.x = _W * 0.5

    capturetitle.y = 80

    

    – MENU BACK BUTTON

    gotoMain = display.newText(“Return to Main Page”, 0, 40, native.systemFont, 80)

    gotoMain:setFillColor(0,0,0)

    gotoMain.x = _W * 0.5

    gotoMain.y = _H - 80

    

    – ENTER BUTTON WIDGET

    enterButton = widget.newButton

    {

        id = “enter button”,

        onRelease = buttonTapped,

        defaultFile = “images/buttontest.png”,

        overFile = “images/buttontest_touch.png”

    }

    enterButton.x = _W * 0.5

    enterButton.y = _H * 0.4

    

    – SCENE GROUPS INSERTS

    sceneGroup:insert( background )

    sceneGroup:insert( capturetitle )

    sceneGroup:insert( gotoMain )

    sceneGroup:insert( enterButton )

    

    – LISTENERS

    – MAIN MENU TEXT BUTTON 

    gotoMain:addEventListener(“touch”, gotoMain)

    – BACKGROUND LISTENER

    background:addEventListener(“tap”, background)

    

    – FUNCTIONS

    – Hide keyboard upon tapping the background

    function background:tap(e)

        native.setKeyboardFocus(nil)

    end

    

    function gotoMain:touch(e)

        if(e.phase == “began”) then

            

            composer.gotoScene( “scenet” )           

        end 

        return true

    end

end

– “scene:show()”

function scene:show( event )

    

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        – Called when the scene is still off screen (but is about to come on screen).

    elseif ( phase == “did” ) then

        – Called when the scene is now on screen.

        – Insert code here to make the scene come alive.

        – Example: start timers, begin animation, play audio, etc.

        

        – Create, Position and instantiate Input Textfield

        username = native.newTextField(0,0, _W * 0.8, 100)

        local font = “HelveticaNeue” or system.nativeFont

        local hintText = “Enter an item to capture”

        username.inputType = “default”

        username.font = native.newFont(font,24)

        username.text = hintText

        username.align = “center”   

        username.x = _W * 0.5

        username.y = _H * 0.2

    end

end

– “scene:hide()”

function scene:hide( event )

    

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        – Called when the scene is on screen (but is about to go off screen).

        – Insert code here to “pause” the scene.

        – Example: stop timers, stop animation, stop audio, etc.

        

        username:removeSelf()

        username = nil

        

        

        

    elseif ( phase == “did” ) then

        – Called immediately after scene goes off screen.

    end

end

– “scene:destroy()”

function scene:destroy( event )

    

    local sceneGroup = self.view

    

    – Called prior to the removal of scene’s view (“sceneGroup”).

    – Insert code here to clean up the scene.

    – Example: remove display objects, save state, etc.

end


– Listener setup

scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene[/lua]

I ran your code above and I don’t get the error.

Rob

Crazy. . . I’ve been continuing writing my app and I still get the error. But it doesn’t seem to effect the app unless I try to load a different device without re-compiling.

Thanks for checking that out on your end Rob.

James

You can certainly forward declare enterButton like you have, but you can also define it in the create() function.  The step you are missing is you are not adding enterButton to your scene’s view group:

sceneGroup:insert(enterButton)

If you do this step, you can create it in scene:create() and all will be right with the world.  When the scene goes away, the button will go with it.  Then you don’t need to explicitly remove it in scene:exit().

Composer works by managing the display objects ( not native ones ) that you insert into the scene’s group.  It will delete the items, transition them on and off the screen as needed.

Rob

Rob,

Thanks for the suggestion.  I had originally build my scene with all display objects in the scene:create() and with adding SQL functionality I started moving things around to make it work. But I have started over and run into the same issue. Below is the new code. I just built it up until I ran into the issue and it didn’t show up until I added the removeSelf() (widget) to the scene:hide().

I guess my issue is with how to I get rid of Native objects from the scene.

complete.lua:116: attempt to index upvalue ‘username’ (a nil value)

message

Thanks for your help in advance. .  .

[lua]

local composer = require( “composer” )

local scene = composer.newScene()


– All code outside of the listener functions will only be executed ONCE

– unless “composer.removeScene()” is called.


– local forward references should go here

local widget = require(“widget”)

local username

local gotoMain


– “scene:create()”

function scene:create( event )

    

    local sceneGroup = self.view

    

    – Initialize the scene here.

    – Example: add display objects to “sceneGroup”, add touch listeners, etc.

    local background = display.newRect( display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight )

    background:setFillColor(255,255,255)

    

    – MAIN TITLE TEXT

    local capturetitle = display.newText(“Capture Page”, 0, 40, native.systemFont, 80)

    capturetitle:setFillColor(0,0,0)

    capturetitle.x = _W * 0.5

    capturetitle.y = 80

    

    – MENU BACK BUTTON

    gotoMain = display.newText(“Return to Main Page”, 0, 40, native.systemFont, 80)

    gotoMain:setFillColor(0,0,0)

    gotoMain.x = _W * 0.5

    gotoMain.y = _H - 80

    

    – ENTER BUTTON WIDGET

    enterButton = widget.newButton

    {

        id = “enter button”,

        onRelease = buttonTapped,

        defaultFile = “images/buttontest.png”,

        overFile = “images/buttontest_touch.png”

    }

    enterButton.x = _W * 0.5

    enterButton.y = _H * 0.4

    

    – SCENE GROUPS INSERTS

    sceneGroup:insert( background )

    sceneGroup:insert( capturetitle )

    sceneGroup:insert( gotoMain )

    sceneGroup:insert( enterButton )

    

    – LISTENERS

    – MAIN MENU TEXT BUTTON 

    gotoMain:addEventListener(“touch”, gotoMain)

    – BACKGROUND LISTENER

    background:addEventListener(“tap”, background)

    

    – FUNCTIONS

    – Hide keyboard upon tapping the background

    function background:tap(e)

        native.setKeyboardFocus(nil)

    end

    

    function gotoMain:touch(e)

        if(e.phase == “began”) then

            

            composer.gotoScene( “scenet” )           

        end 

        return true

    end

end

– “scene:show()”

function scene:show( event )

    

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        – Called when the scene is still off screen (but is about to come on screen).

    elseif ( phase == “did” ) then

        – Called when the scene is now on screen.

        – Insert code here to make the scene come alive.

        – Example: start timers, begin animation, play audio, etc.

        

        – Create, Position and instantiate Input Textfield

        username = native.newTextField(0,0, _W * 0.8, 100)

        local font = “HelveticaNeue” or system.nativeFont

        local hintText = “Enter an item to capture”

        username.inputType = “default”

        username.font = native.newFont(font,24)

        username.text = hintText

        username.align = “center”   

        username.x = _W * 0.5

        username.y = _H * 0.2

    end

end

– “scene:hide()”

function scene:hide( event )

    

    local sceneGroup = self.view

    local phase = event.phase

    

    if ( phase == “will” ) then

        – Called when the scene is on screen (but is about to go off screen).

        – Insert code here to “pause” the scene.

        – Example: stop timers, stop animation, stop audio, etc.

        

        username:removeSelf()

        username = nil

        

        

        

    elseif ( phase == “did” ) then

        – Called immediately after scene goes off screen.

    end

end

– “scene:destroy()”

function scene:destroy( event )

    

    local sceneGroup = self.view

    

    – Called prior to the removal of scene’s view (“sceneGroup”).

    – Insert code here to clean up the scene.

    – Example: remove display objects, save state, etc.

end


– Listener setup

scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene[/lua]

I ran your code above and I don’t get the error.

Rob

Crazy. . . I’ve been continuing writing my app and I still get the error. But it doesn’t seem to effect the app unless I try to load a different device without re-compiling.

Thanks for checking that out on your end Rob.

James