Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Tableview crash when asynch download image in row (bad argument #-1 to 'newImage' (Proxy expected, got nil))
Started by GBF Comm Jan 18 2018 08:42 AM

2 replies to this topic
tableview runtime error asynchronous network.download bad argument #-1 to newimage proxy expected

Best Answer GBF Comm , 25 January 2018 - 12:47 AM

Hi Rob,
After all, thank you very much for responding quickly.
It is indeed what it seemed to me. The NetworkListener arriving while Row was unloaded because off the screen.
However, I did it that way and it worked well with the 2017 build I had. I tested in the onRowRender if the image file was already cached, and if not I performed the networkDownload.
Your solution unfortunately suits me only half, because if I start uploading images to the insertion of the Row and the Row is displayed while the image is not yet downloaded, I will have a row without image.
 
Anyway, I think I just solved my runtime problem by conditioning the display of the image in case of NetworkDownload with this condition:
 
 
if (row._proxy) then
 local img = display.newImage (row, event.response.filename, event.response.baseDirectory, 60, 40)
......
else
print ("the row does not exist anymore")
end

 
I no longer have a Runtime error and my application is working again as before.
Hoping it can help others in my case.
 
Thank you very much for responding to my message. Your help is always precious Rob. Have a nice day!

[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

GBF Comm

[GLOBAL: userInfoPane.html]
GBF Comm
  • Enthusiast

  • 35 posts
  • Corona SDK

Hello,
I migrated from v2017.3073 to v2018.3204, and a lot of runtime errors appears in my app.
 
 
I isolated the problem and tried to reproduce the issue in the sample "Widget" Corona (I reduce the code to a minimum).
It looks like the runtime error is related to the asynchronous image loading I do in the onRowRender function of the TableView.
When I manipulate quickly the tableView up and down, the runtime error occure.
 
ERROR: Runtime error
main.lua:40: bad argument #-1 to 'newImage' (Proxy expected, got nil)
 
It seems that sometimes the var "row" (event.row) used to attach image is not defined, i don't know why. I didn't find any solution.
am i doing something wrong? is it a bug i have to report?
 
 
In advance thank you to the person who will take the time to read my post and will bring me a beginning of solution.
 
PS: sorry for my bad english.

Here is the code of my main.lua

Have a nice day!

local widget = require( "widget" )
-- Forward reference for the tableView
	local tableView

	-- Listen for tableView events
	local function tableViewListener( event )
		local phase = event.phase
		--print( "Event.phase is:", event.phase )
	end

	-- Handle row rendering
	local function onRowRender( event )
		local phase = event.phase
		local row = event.row

		local groupContentHeight = row.contentHeight
		
		local rowTitle = display.newText( row, "Row " .. row.index, 0, 0, nil, 14 )
		rowTitle.x = 10
		rowTitle.anchorX = 0
		rowTitle.y = groupContentHeight * 0.5
		if ( row.isCategory ) then
			rowTitle:setFillColor( 1 )
			rowTitle.text = rowTitle.text.." (category)"
		else
			rowTitle:setFillColor( 0 )




			--[[ ASYNC DOWLOAD IMAGE ]]
			--[[ CODE FROM THE SAMPLE AsynchImageDownload ]]

			local myImage

			local function networkListener( event )
				if ( event.isError ) then
					print ( "Network error - download failed" )
				else
					myImage = display.newImage(row, event.response.filename, event.response.baseDirectory, 20, 20)
					myImage.alpha = 0
					myImage.x = display.contentWidth - 50
					myImage.y = 75
					myImage.width = 120
					myImage.height = 120
					transition.to( myImage, { alpha = 1.0 } )
					print ( "RESPONSE: ", event.response.filename )
				end
			end

			network.download( 
				"https://developer.coronalabs.com/demo/hello.png", 
				"GET", 
				networkListener, 
				"helloCopy.png", 
				system.TemporaryDirectory )

			end	

			--[[ / ADD BY ME ]]




	end
	
	-- Handle row updates
	local function onRowUpdate( event )
		local phase = event.phase
		local row = event.row
		--print( row.index, ": is now onscreen" )
	end
	
	-- Handle touches on the row
	local function onRowTouch( event )
		local phase = event.phase
		local row = event.target
		if ( "release" == phase ) then
		end
	end
	
	-- Create a tableView
	tableView = widget.newTableView
	{
		top = 0,
		left = 0,
		width = display.contentWidth, 
		height = display.contentHeight,
		hideBackground = true,
		listener = tableViewListener,
		onRowRender = onRowRender,
		onRowUpdate = onRowUpdate,
		onRowTouch = onRowTouch,
	}
	

	-- Create 75 rows
	for i = 1,75 do
		local isCategory = false
		local rowHeight = 150
		local rowColor = { 
			default = { 1 },
			over = { 1 }
		}
		-- Make some rows categories
		if i == 20 or i == 40 or i == 60 then
			isCategory = true
			rowHeight = 32
			rowColor = {
				default = { 0.5 },
				over = { 0.5 }
			}
		end
		-- Insert the row into the tableView
		tableView:insertRow
		{
			isCategory = isCategory,
			rowHeight = rowHeight,
			rowColor = rowColor,
			lineColor = { 0.5 },
			params = { }
		}
	end


 

 



[TOPIC: post.html]
#2

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,925 posts
  • Enterprise

The problem is kinda complex. There are a few things fighting you here.

 

First, you're loading up a table with more rows than it can display. For efficiency, a tableView destroys (culls) rows that are not on screen. When the row is brought on screen, then the onRowRender function is called. This leads to the second problem.

 

You're calling network.download() which is an asynchronous call. It takes time to download that image and the image is being rendered in the networkListener function. Because network.download returns immediately, the row will render quickly, except for the image. You wouldn't want network.download to block your UI while it's downloading dozens of images and every time you tried to scroll an image on screen. If you scroll your tableView and a row that was on screen and still waiting on it's image to download goes off screen, that row gets culled but the network.download() call is still active and it's trying to render to a row that doesn't exist.

 

I would consider downloading the images outside of the onRowRender function and store the images in a separate Lua table and have onRowRender check to see if the image table has a display object and display it if it does.  At a minimum you need to make sure you have a valid row before you try to insert an image into it. If the row doesn't exist then don't add the image to it and maybe consider removing the image. I think this would result in more network traffic than the first suggestion.  The other option is to use network download to just cache the file to system.CachesDirectory, starting the network.request() when you insert the rows and pass the expected file name to onRowRender in params and then have onRowRender just try and load the cached file.  This would likely be the most network efficient model because you can let caching work for you.

 

Rob



[TOPIC: post.html]
#3

GBF Comm

[GLOBAL: userInfoPane.html]
GBF Comm
  • Enthusiast

  • 35 posts
  • Corona SDK

  Best Answer

Hi Rob,
After all, thank you very much for responding quickly.
It is indeed what it seemed to me. The NetworkListener arriving while Row was unloaded because off the screen.
However, I did it that way and it worked well with the 2017 build I had. I tested in the onRowRender if the image file was already cached, and if not I performed the networkDownload.
Your solution unfortunately suits me only half, because if I start uploading images to the insertion of the Row and the Row is displayed while the image is not yet downloaded, I will have a row without image.
 
Anyway, I think I just solved my runtime problem by conditioning the display of the image in case of NetworkDownload with this condition:
 
 
if (row._proxy) then
 local img = display.newImage (row, event.response.filename, event.response.baseDirectory, 60, 40)
......
else
print ("the row does not exist anymore")
end

 
I no longer have a Runtime error and my application is working again as before.
Hoping it can help others in my case.
 
Thank you very much for responding to my message. Your help is always precious Rob. Have a nice day!



[topic_controls]
[/topic_controls]