Appending dynamically created objects to an array

I have a feeling this is a newbie error but I’ve search the documentation and I can’t solve it, so here goes:

I have a RecordSet I iterate thru and populate a new instance of a class (AIMRecord), and append to an array. Code looks like this:

. . . Dim result(-1) as AIMRecord While Not data.EOF if display then dim rec as new AIMRecord rec.load( data ) result.Append( rec) end data.MoveNext wend data.close db.close

When I set a breakpoint inside the loop and inspect an instance of rec, it looks fine, so the load method is grabbing the data from the current record in the RecordSet and populating the instance correctly (fwiw, I’m storing the data inside AIMRecord using a dictionary)

However, when I set a breakpoint after the loop and inspect the results array, everything looks fine - the instance count is correct and drilling down to a specific instance also looks populated correctly, but if I try to see an actual data value within the AIMRecord, Windows reports that the application has stopped working. If I let the app run, when I try to iterate thru the result array and display the data in a listbox, the data is just blank…

Is there anything above obviously wrong ? I’m baffled… Thanks

Can you reproduce this with a small example?

Not sure how to make a smaller example than this:

This code is attached to button action event and I have simple textarea for debugging:

[code] Dim db As New ODBCDatabase

db.DataSource = “Driver={Microsoft Access Driver (*.mdb)};Dbq=c:\Users\PTanguay\Dropbox\AIMDB.mdb;Uid=XXXX;Pwd=XXXX;”

If db.Connect = false Then
return
end

dim data as recordset = db.SQLSelect("SELECT * FROM AIM Data Records" )
dim result(-1) as AIMRecord

While Not data.EOF
dim rec as new AIMRecord
rec.load( data )
// this shows the correct value
window1.TextArea1.Text=Window1.TextArea1.Text+chr(13)+"#######: " + rec.dataset.Value(“DB ID Number”)
result.Append( rec )
data.MoveNext
wend

data.Close
db.Close

dim cpt as integer = 1
for each r as AIMRecord in result
// this shows blank values
window1.TextArea1.Text=Window1.TextArea1.Text+chr(13)+ str(cpt) + " ****: " + r.dataset.Value(“DB ID Number”)
cpt=cpt+1
next[/code]

This code is the load AIMRecord.load method (data as RecordSet)

[code] dim fields(-1) as string = array( “DB ID Number”, “Record Status”, “Category”, “Sub Category”, “Record Type”, “Identifier”, “Inspection Type”, _
“F_IA”, “F_AR”, “F_S”,“F_US”,“F_NA”,“F_NI”,“F_PI”,“F_RI”,“F_M”,“F_ATTACH”,“F_WO_REQ”,“F_WO_COMP”,“Map Number”, _
“GPS Latitude”, “GPS Longitude”, “GPS Quality”, “Creation DateTime”, “Last Modified DateTime”, “Comments” )

for each f as string in fields
me.dataset.Value( f ) = dbdata.Field( f )
next
// this shows the correct value
Window1.TextArea1.Text=Window1.TextArea1.Text + chr(13)+ "id: " + me.dataset.Value(“DB ID Number”) [/code]

The AIMRecord constructor has 1 line: me.dataset = new Dictionary

I would expect this line to actually be this:

As Paul pointed out, this is the source of your error. You’re saving a reference to the database field itself, which is the same on each iteration and is finally empty when your loop ends. Save the value instead.

Aaaand sure enough, that was indeed the problem! Thank you both.

Additional question regarding memory management: later on when I want to get rid of all the objects I new’ed above, can I just set result to nil, or should I iterate thru the array and set each element to nil ?

Thanks again!

[quote=45903:@Philippe Tanguay]Additional question regarding memory management: later on when I want to get rid of all the objects I new’ed above, can I just set result to nil, or should I iterate thru the array and set each element to nil ?

Thanks again![/quote]
You don’t need to worry about rec, it goes out of scope at the end of every for loop iteration. Same with result, at the end of the action event, it will go out of scope and automatically cleaned up, so you don’t need to worry about them. I think that’s what you were asking?

If you were looking to reuse result in the same event before its end and you wanted to clear it, then you could use ReDim result(-1) and it will be as if you had newly declared it.

I wasn’t worried about rec, but ‘result’ was really just a something I used for the demo code. In my real app, I intend to have a similar variable instantiated for the life of the app which will hold the currently displayed dataset for manipulation. If/when the user changes the selection criteria, I need to blow away the current dataset and replace it with the new one. So this var will never really go out of scope - I need to clear its content and replace it. Make sense?

Redim it to have no elements before filling it and that will get rid of any references its holding on to
IF this is the only reference then that will free up the memory
See http://documentation.xojo.com/index.php/Redim

Yeah that makes sense. If you make the variable a window or module property (as you will need to do) then you can still use ReDim result(-1) then append the new records when needed.

Very nice, that’s far more elegant than a loop. Thanks again everyone !