App Crashes On Only On Devices

I have an application that has been working fine on the simulator and when I build it for Xcode but as soon as I put it on a device it crashes.  The startup screen shows for a long time then the app just closes.  I have tried it on a couple of iPads and the same thing happens on both.  I have attached the Device Log from the iPad but I am new to this and have no idea what I am looking for.  The process for this application is called mixupdressup_sto.  PLEASE HELP, I have no idea what to do about this.

Thanks!

Aaron Williams

Hi Aaron.  There are a few very common causes of “It works in the simulator and not on the device”.  The first and most common has to do with case sensitivity of file names.  The simulator ignores the case for file names, however the devices are case sensitive.   So if you have an image named “MyImage.PNG” and you are trying to do:  myPic = display.newImage(“myimage.png”) then this will work perfectly fine in the simulator and will crash the smithereens out of your app on the device.  Scrub your code looking for images, sprite sheets, audio files or any thing you are doing a “require” to or any Storyboard/Director module names.

The second common problem is an error in your build.settings file.

How do you find it?  With your device tethered to your computer launch XCode’s Organizer.  You will see your device show up on the left hand side and underneath it will be an entry called “Console Log”.  Click on that and you will see all the log messages going to the device.   Start up your app and watch for messages from your app or anything that looks like a Lua pcall() error.  That can help you narrow down the cause.  You may need to put some print statements in to narrow down the problem.

Thanks for the quick response!!  After playing with it some more I have narrowed down the problem a little: 

my app is a dress-up game that has a variety of outfits, hairstyles, shoes etc that are each a seperate png file.  I recently quadrupled the number of outfits and I believe it is now causing a memory error because when I changed the code and cut back the number of loaded images the app worked again on my iPad.  I must be reaching some sort of memory limitations that only show up on an actual device.

As I am very new to this, any advice on watching and managing memory - especially when it comes to large numbers of images - would be greatly appreciated.  Is there anyway in the simulator to simulate the memory limitations of an actual iPad or iPhone?

Thanks again for your quick response and help.

Well, your Mac probably has 4-8 GB of memory.  Your device is probably 0.5-1GB of memory, it is really easy to overwhelm the memory of the device.  What are the pixel sizes of your outfits?  Also if you can post your config.lua would help too as well as an example of where you’re loading some of your images.

Thanks

Rob

I have attached my config.lua file.  The pictures are divided into three segments - heads, bodies and feet.  There are 43 heads and approximately 120 bodies and 120 feet.  Currently I have all these images loading up into their own display.image objects at startup but it seems like maybe I need to be smarter about adding and removing image objects as they are needed.

The images are all 50k or less but they are in the png24 format.  Do you think that trying to recreate them as png8 files would save a lot of memory?

Also, the images are loaded at the beginning using this SlideView.lua code I found on the site and slightly modified.  This object is called 7 times with an array of approximately 40 images each time.

png8 or png24/32 doesn’t matter for in-memory usage, only on storage size.

I don’t see your config.lua.  Copy/paste it into the edit box of the fourm inside of [lua] and [/lua] tags (removing the spaces between the [and the lua].  I need to know the pixel dimensions of the images (or a few of them) like 320x480 64x95, etc.  It looks like your code didn’t post.

Here is my config.lua:

[lua]

application =

{

    content =

    {

        width = 768,

        height = 1024,

        scale = “zoomeven”,

        imageSuffix =

        {

           ["@2"] = 2,

        }

    },

}

[/lua]

The image files for the outfits are:  

“head” images - 768 X 382

“dress” images - 768 X 265

“legs” images - 768 X 274

Here is the slideView.lua file which is called like this:  

slideViewHead = slideView.new( myHeads , nil, headTop, 265, callBackFromSlider)

[lua]

module(…, package.seeall)

function new( imageSet, slideBackground, top, slideHeight, callback )    

local screenW, screenH = display.contentWidth, slideHeight 

local viewableScreenW, viewableScreenH = display.viewableContentWidth, slideHeight 

local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, 0

local imgNum = nil

local images = nil

local touchListener, nextImage, prevImage, cancelMove, initImage

local background

local imageNumberText, imageNumberTextShadow

local imageDirectory = “images/girls/”

    local pad = 20

    local top = top or 0 

    local bottom = bottom or 0

    local g = display.newGroup()

        

    background = display.newRect( 0, 0, screenW, screenH )

    background:setFillColor(110, 110, 0, 0)

    g:insert(background)

    

    images = {}

    for i = 1,#imageSet do

        local fileName = imageDirectory … imageSet[i]

        print( fileName )

        local p = display.newImage( fileName )

        local h = viewableScreenH

        g:insert§

        --print(“yScale=”…tostring(p.yScale))

        --print(“xScale=”…tostring(p.xScale))

        

        if (i > 1) then

            p.x = screenW*1.5 + pad – all images offscreen except the first one

        else 

            p.x = screenW*.5

        end

        

        p.y = h*.5

        images[i] = p

    end

    

    imgNum = 1

    

    g.x = 0

    g.y = top

            

    function touchListener (self, touch) 

        local phase = touch.phase

        print(“slides”, phase)

        if ( phase == “began” ) then

            – Subsequent touch events will target button even if they are outside the contentBounds of button

            display.getCurrentStage():setFocus( self )

            self.isFocus = true

            startPos = touch.x

            prevPos = touch.x

            

            

                                    

        elseif( self.isFocus ) then

        

            if ( phase == “moved” ) then

            

                

                        

                if tween then transition.cancel(tween) end

    

                print(imgNum)

                

                local delta = touch.x - prevPos

                prevPos = touch.x

                

                images[imgNum].x = images[imgNum].x + delta

                

                if (images[imgNum-1]) then

                    images[imgNum-1].x = images[imgNum-1].x + delta

                end

                

                if (images[imgNum+1]) then

                    images[imgNum+1].x = images[imgNum+1].x + delta

                end

            elseif ( phase == “ended” or phase == “cancelled” ) then

                

                dragDistance = touch.x - startPos

                print("dragDistance: " … dragDistance)

                

                if (dragDistance < -40 and imgNum < #images) then

                    nextImage()

                elseif (dragDistance > 40 and imgNum > 1) then

                    prevImage()

                else

                    cancelMove()

                end

                                    

                if ( phase == “cancelled” ) then        

                    cancelMove()

                end

                – Allow touch events to be sent normally to the objects they “hit”

                display.getCurrentStage():setFocus( nil )

                self.isFocus = false

                                                        

            end

        end

                    

        return true

        

    end

    

    

    function cancelTween()

        if prevTween then 

            transition.cancel(prevTween)

        end

        prevTween = tween 

    end

    

    function nextImage()

        print( “in nextImage” )

        print( swishSound )

        audio.play( swishSound, fxChannel )

        tween = transition.to( images[imgNum], {time=400, x=(screenW*.5 + pad)*-1, transition=easing.outExpo } )

        tween = transition.to( images[imgNum+1], {time=400, x=screenW*.5, transition=easing.outExpo } )

        imgNum = imgNum + 1

        initImage(imgNum)

        callback(g)

    end

    

    function prevImage()

        audio.play( swishSound, fxChannel )

        tween = transition.to( images[imgNum], {time=400, x=screenW*1.5+pad, transition=easing.outExpo } )

        tween = transition.to( images[imgNum-1], {time=400, x=screenW*.5, transition=easing.outExpo } )

        imgNum = imgNum - 1

        initImage(imgNum)

        callback(g)

    end

    

    function cancelMove()

        tween = transition.to( images[imgNum], {time=400, x=screenW*.5, transition=easing.outExpo } )

        tween = transition.to( images[imgNum-1], {time=400, x=(screenW*.5 + pad)*-1, transition=easing.outExpo } )

        tween = transition.to( images[imgNum+1], {time=400, x=screenW*1.5+pad, transition=easing.outExpo } )

    end

    

    function initImage(num)

        --print( pad )

        if (num < #images) then

            images[num+1].x = screenW*1.5 + pad            

        end

        if (num > 1) then

            images[num-1].x = (screenW*.5 + pad)*-1

        end

        print( "imgnum is " … imgNum )

        print( "imagefile is " … imageSet[imgNum]:sub(-6))

    end

    function tapListener()

        print(“in the tap event”)

        --storyboard.hideOverlay()

           --make sure there is not a sound already playing

           if audio.isChannelPlaying( soundChannel ) or soundMode == “None” then

               --don’t do anything

           else

               testChannel = audio.play( girlSound, soundChannel )

           end

    end

    background.tap = tapListener

    background:addEventListener( “tap”, background )

    background.touch = touchListener

    background:addEventListener( “touch”, background )

    ------------------------

    – Define public methods

    function getImageNumber( nameIn )

        if nameIn:sub(1,4) == “head” then

            print(“its a head”)

            if #nameIn == 9 then

                return tonumber(nameIn:sub(5,5))

            else

                return tonumber(nameIn:sub(5,6))

            end

        else

            print(“not a head”)

            return 0

        end

    end

    function g:getSkinTone()

        print(“The image number is:”…getImageNumber( imageSet[imgNum] ))

        local imageNumber = getImageNumber( imageSet[imgNum] )

        if imageNumber == 4 or imageNumber == 7 or imageNumber == 9 or imageNumber == 15  or imageNumber == 16 or imageNumber == 18 or imageNumber == 27 then

            return “tan”

        elseif imageNumber == 11 or imageNumber == 2  or imageNumber == 8  or imageNumber == 19 or imageNumber == 33 or imageNumber == 35 or imageNumber == 36 or imageNumber == 43 or imageNumber == 21 then

            return “Asian”

        elseif imageNumber > 0 then

            return “peach”

        else

            return “n/a”

        end

    end

    function g:isHead()

        print(imageSet[imgNum]:sub(1,4))

        if imageSet[imgNum]:sub(1,4) == “head” then

            return true

        else

            return false

        end

    end

    

    function g:jumpToImage(num)

        local i

        print(“jumpToImage”)

        print("#images", #images)

        for i = 1, #images do

            if i < num then

                images[i].x = -screenW*.5;

            elseif i > num then

                images[i].x = screenW*1.5 + pad

            else

                images[i].x = screenW*.5

            end

        end

        --print( pad)

        imgNum = num

        initImage(imgNum)

    end

    function g:cleanUp()

        print(“slides cleanUp”)

        background:removeEventListener(“touch”, touchListener)

    end

    function g:getCurrentImage()

        return imgNum

    end

    return g    

end

[/lua]

When I add the function monitorMem from the article:  Corona SDK Memory Leak Prevention 101, I get the following values when I loaded all 43 dresses, heads and shoes:

MemUsage: 380.951171875

TexMem:      661.783168

Does anyone know what would be acceptable values for these fields?

You certainly have a memory problem.

MemUsage isn’t too much to worry about.  That number is in K bytes (multiply by 1024 to get the real amount in bytes), and 380K is tiny amount of memory.  One sounds or one graphic is likely to consume more memory.

TexMem: is your texture memory.  This is where your images live.  That number is expressed in Megabytes  or Millions of bytes.  You’re using 661MB of memory.  Given that iPad 2’s and iPhone 4’s only have 512MB of memory you are very much running out.  The iPad 3/4 and IPhone 5 only have 1GB (1024MB) of memory and give the operating system and other things consume part of it, you are likely using more memory than the OS can give you.

Why is your memory usage so high?  It’s your images.  For instance your head images are 768 X 382.  In OpenGL, the underlying graphics engine, this rounds up to 1024x512 in size; however there  are four color channels which means that the total memory for one image is 1024x512x4 or in this case 2MB each.   I doubt that each head image is really that size.  I suspect you have a bunch of transparent background.  All of that transparency counts towards your memory usage.   If you can trim your images it will get you a considerable amount of memory back.

You can either do that, or only load the images you are currently using (which will probably lead to slow downs while loading various images.)

Hi Aaron.  There are a few very common causes of “It works in the simulator and not on the device”.  The first and most common has to do with case sensitivity of file names.  The simulator ignores the case for file names, however the devices are case sensitive.   So if you have an image named “MyImage.PNG” and you are trying to do:  myPic = display.newImage(“myimage.png”) then this will work perfectly fine in the simulator and will crash the smithereens out of your app on the device.  Scrub your code looking for images, sprite sheets, audio files or any thing you are doing a “require” to or any Storyboard/Director module names.

The second common problem is an error in your build.settings file.

How do you find it?  With your device tethered to your computer launch XCode’s Organizer.  You will see your device show up on the left hand side and underneath it will be an entry called “Console Log”.  Click on that and you will see all the log messages going to the device.   Start up your app and watch for messages from your app or anything that looks like a Lua pcall() error.  That can help you narrow down the cause.  You may need to put some print statements in to narrow down the problem.

Thanks for the quick response!!  After playing with it some more I have narrowed down the problem a little: 

my app is a dress-up game that has a variety of outfits, hairstyles, shoes etc that are each a seperate png file.  I recently quadrupled the number of outfits and I believe it is now causing a memory error because when I changed the code and cut back the number of loaded images the app worked again on my iPad.  I must be reaching some sort of memory limitations that only show up on an actual device.

As I am very new to this, any advice on watching and managing memory - especially when it comes to large numbers of images - would be greatly appreciated.  Is there anyway in the simulator to simulate the memory limitations of an actual iPad or iPhone?

Thanks again for your quick response and help.

Well, your Mac probably has 4-8 GB of memory.  Your device is probably 0.5-1GB of memory, it is really easy to overwhelm the memory of the device.  What are the pixel sizes of your outfits?  Also if you can post your config.lua would help too as well as an example of where you’re loading some of your images.

Thanks

Rob

I have attached my config.lua file.  The pictures are divided into three segments - heads, bodies and feet.  There are 43 heads and approximately 120 bodies and 120 feet.  Currently I have all these images loading up into their own display.image objects at startup but it seems like maybe I need to be smarter about adding and removing image objects as they are needed.

The images are all 50k or less but they are in the png24 format.  Do you think that trying to recreate them as png8 files would save a lot of memory?

Also, the images are loaded at the beginning using this SlideView.lua code I found on the site and slightly modified.  This object is called 7 times with an array of approximately 40 images each time.

png8 or png24/32 doesn’t matter for in-memory usage, only on storage size.

I don’t see your config.lua.  Copy/paste it into the edit box of the fourm inside of [lua] and [/lua] tags (removing the spaces between the [and the lua].  I need to know the pixel dimensions of the images (or a few of them) like 320x480 64x95, etc.  It looks like your code didn’t post.

Here is my config.lua:

[lua]

application =

{

    content =

    {

        width = 768,

        height = 1024,

        scale = “zoomeven”,

        imageSuffix =

        {

           ["@2"] = 2,

        }

    },

}

[/lua]

The image files for the outfits are:  

“head” images - 768 X 382

“dress” images - 768 X 265

“legs” images - 768 X 274

Here is the slideView.lua file which is called like this:  

slideViewHead = slideView.new( myHeads , nil, headTop, 265, callBackFromSlider)

[lua]

module(…, package.seeall)

function new( imageSet, slideBackground, top, slideHeight, callback )    

local screenW, screenH = display.contentWidth, slideHeight 

local viewableScreenW, viewableScreenH = display.viewableContentWidth, slideHeight 

local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, 0

local imgNum = nil

local images = nil

local touchListener, nextImage, prevImage, cancelMove, initImage

local background

local imageNumberText, imageNumberTextShadow

local imageDirectory = “images/girls/”

    local pad = 20

    local top = top or 0 

    local bottom = bottom or 0

    local g = display.newGroup()

        

    background = display.newRect( 0, 0, screenW, screenH )

    background:setFillColor(110, 110, 0, 0)

    g:insert(background)

    

    images = {}

    for i = 1,#imageSet do

        local fileName = imageDirectory … imageSet[i]

        print( fileName )

        local p = display.newImage( fileName )

        local h = viewableScreenH

        g:insert§

        --print(“yScale=”…tostring(p.yScale))

        --print(“xScale=”…tostring(p.xScale))

        

        if (i > 1) then

            p.x = screenW*1.5 + pad – all images offscreen except the first one

        else 

            p.x = screenW*.5

        end

        

        p.y = h*.5

        images[i] = p

    end

    

    imgNum = 1

    

    g.x = 0

    g.y = top

            

    function touchListener (self, touch) 

        local phase = touch.phase

        print(“slides”, phase)

        if ( phase == “began” ) then

            – Subsequent touch events will target button even if they are outside the contentBounds of button

            display.getCurrentStage():setFocus( self )

            self.isFocus = true

            startPos = touch.x

            prevPos = touch.x

            

            

                                    

        elseif( self.isFocus ) then

        

            if ( phase == “moved” ) then

            

                

                        

                if tween then transition.cancel(tween) end

    

                print(imgNum)

                

                local delta = touch.x - prevPos

                prevPos = touch.x

                

                images[imgNum].x = images[imgNum].x + delta

                

                if (images[imgNum-1]) then

                    images[imgNum-1].x = images[imgNum-1].x + delta

                end

                

                if (images[imgNum+1]) then

                    images[imgNum+1].x = images[imgNum+1].x + delta

                end

            elseif ( phase == “ended” or phase == “cancelled” ) then

                

                dragDistance = touch.x - startPos

                print("dragDistance: " … dragDistance)

                

                if (dragDistance < -40 and imgNum < #images) then

                    nextImage()

                elseif (dragDistance > 40 and imgNum > 1) then

                    prevImage()

                else

                    cancelMove()

                end

                                    

                if ( phase == “cancelled” ) then        

                    cancelMove()

                end

                – Allow touch events to be sent normally to the objects they “hit”

                display.getCurrentStage():setFocus( nil )

                self.isFocus = false

                                                        

            end

        end

                    

        return true

        

    end

    

    

    function cancelTween()

        if prevTween then 

            transition.cancel(prevTween)

        end

        prevTween = tween 

    end

    

    function nextImage()

        print( “in nextImage” )

        print( swishSound )

        audio.play( swishSound, fxChannel )

        tween = transition.to( images[imgNum], {time=400, x=(screenW*.5 + pad)*-1, transition=easing.outExpo } )

        tween = transition.to( images[imgNum+1], {time=400, x=screenW*.5, transition=easing.outExpo } )

        imgNum = imgNum + 1

        initImage(imgNum)

        callback(g)

    end

    

    function prevImage()

        audio.play( swishSound, fxChannel )

        tween = transition.to( images[imgNum], {time=400, x=screenW*1.5+pad, transition=easing.outExpo } )

        tween = transition.to( images[imgNum-1], {time=400, x=screenW*.5, transition=easing.outExpo } )

        imgNum = imgNum - 1

        initImage(imgNum)

        callback(g)

    end

    

    function cancelMove()

        tween = transition.to( images[imgNum], {time=400, x=screenW*.5, transition=easing.outExpo } )

        tween = transition.to( images[imgNum-1], {time=400, x=(screenW*.5 + pad)*-1, transition=easing.outExpo } )

        tween = transition.to( images[imgNum+1], {time=400, x=screenW*1.5+pad, transition=easing.outExpo } )

    end

    

    function initImage(num)

        --print( pad )

        if (num < #images) then

            images[num+1].x = screenW*1.5 + pad            

        end

        if (num > 1) then

            images[num-1].x = (screenW*.5 + pad)*-1

        end

        print( "imgnum is " … imgNum )

        print( "imagefile is " … imageSet[imgNum]:sub(-6))

    end

    function tapListener()

        print(“in the tap event”)

        --storyboard.hideOverlay()

           --make sure there is not a sound already playing

           if audio.isChannelPlaying( soundChannel ) or soundMode == “None” then

               --don’t do anything

           else

               testChannel = audio.play( girlSound, soundChannel )

           end

    end

    background.tap = tapListener

    background:addEventListener( “tap”, background )

    background.touch = touchListener

    background:addEventListener( “touch”, background )

    ------------------------

    – Define public methods

    function getImageNumber( nameIn )

        if nameIn:sub(1,4) == “head” then

            print(“its a head”)

            if #nameIn == 9 then

                return tonumber(nameIn:sub(5,5))

            else

                return tonumber(nameIn:sub(5,6))

            end

        else

            print(“not a head”)

            return 0

        end

    end

    function g:getSkinTone()

        print(“The image number is:”…getImageNumber( imageSet[imgNum] ))

        local imageNumber = getImageNumber( imageSet[imgNum] )

        if imageNumber == 4 or imageNumber == 7 or imageNumber == 9 or imageNumber == 15  or imageNumber == 16 or imageNumber == 18 or imageNumber == 27 then

            return “tan”

        elseif imageNumber == 11 or imageNumber == 2  or imageNumber == 8  or imageNumber == 19 or imageNumber == 33 or imageNumber == 35 or imageNumber == 36 or imageNumber == 43 or imageNumber == 21 then

            return “Asian”

        elseif imageNumber > 0 then

            return “peach”

        else

            return “n/a”

        end

    end

    function g:isHead()

        print(imageSet[imgNum]:sub(1,4))

        if imageSet[imgNum]:sub(1,4) == “head” then

            return true

        else

            return false

        end

    end

    

    function g:jumpToImage(num)

        local i

        print(“jumpToImage”)

        print("#images", #images)

        for i = 1, #images do

            if i < num then

                images[i].x = -screenW*.5;

            elseif i > num then

                images[i].x = screenW*1.5 + pad

            else

                images[i].x = screenW*.5

            end

        end

        --print( pad)

        imgNum = num

        initImage(imgNum)

    end

    function g:cleanUp()

        print(“slides cleanUp”)

        background:removeEventListener(“touch”, touchListener)

    end

    function g:getCurrentImage()

        return imgNum

    end

    return g    

end

[/lua]

When I add the function monitorMem from the article:  Corona SDK Memory Leak Prevention 101, I get the following values when I loaded all 43 dresses, heads and shoes:

MemUsage: 380.951171875

TexMem:      661.783168

Does anyone know what would be acceptable values for these fields?

You certainly have a memory problem.

MemUsage isn’t too much to worry about.  That number is in K bytes (multiply by 1024 to get the real amount in bytes), and 380K is tiny amount of memory.  One sounds or one graphic is likely to consume more memory.

TexMem: is your texture memory.  This is where your images live.  That number is expressed in Megabytes  or Millions of bytes.  You’re using 661MB of memory.  Given that iPad 2’s and iPhone 4’s only have 512MB of memory you are very much running out.  The iPad 3/4 and IPhone 5 only have 1GB (1024MB) of memory and give the operating system and other things consume part of it, you are likely using more memory than the OS can give you.

Why is your memory usage so high?  It’s your images.  For instance your head images are 768 X 382.  In OpenGL, the underlying graphics engine, this rounds up to 1024x512 in size; however there  are four color channels which means that the total memory for one image is 1024x512x4 or in this case 2MB each.   I doubt that each head image is really that size.  I suspect you have a bunch of transparent background.  All of that transparency counts towards your memory usage.   If you can trim your images it will get you a considerable amount of memory back.

You can either do that, or only load the images you are currently using (which will probably lead to slow downs while loading various images.)