My app saves incorrect data to file

I have made a container control named myChart.
myChart displays user’s activity in each hour as a percent of total activity over 24 hours. (displays which hours the user was most active)

myChart has 24 integer properties: hour1, hour2, … , hour24 for storing values for each hour.

The values are saved as a textfile in a subfolder inside Application Support.

The values are read at app’s open event,
And it is saved at app’s close event.

The reading works fine (confirmed by feeding a textfile I made with TextMate with random values for 24 hours to the app. the chart was loaded from the random values, and displayed correctly)

But when the app is closed, the file’s values are all saved as zero. all I get is 24 zeros.

Please help me.

Here’s the codes
Please tell me what’s wrong.
#################

code for app open event

[code] dim historyFile as folderItem
dim buffer as TextInputStream

// create a file and a folder
historyFile = SpecialFolder.ApplicationData.Child(“inc.mycompany.myapp”).Child(“myapp_history”)

// If available, reads the preferences file
if historyFile.Exists then
buffer = TextInputStream.Open(historyFile)
wMain.lBreakTime.Text = buffer.ReadLine

wMain.myChart.hour1 = Val(buffer.ReadLine)
wMain.myChart.hour2 = Val(buffer.ReadLine)
wMain.myChart.hour3 = Val(buffer.ReadLine)
wMain.myChart.hour4 = Val(buffer.ReadLine)
wMain.myChart.hour5 = Val(buffer.ReadLine)
wMain.myChart.hour6 = Val(buffer.ReadLine)
wMain.myChart.hour7 = Val(buffer.ReadLine)
wMain.myChart.hour8 = Val(buffer.ReadLine)
wMain.myChart.hour9 = Val(buffer.ReadLine)
wMain.myChart.hour10 = Val(buffer.ReadLine)
wMain.myChart.hour11 = Val(buffer.ReadLine)
wMain.myChart.hour12 = Val(buffer.ReadLine)
wMain.myChart.hour13 = Val(buffer.ReadLine)
wMain.myChart.hour14 = Val(buffer.ReadLine)
wMain.myChart.hour15 = Val(buffer.ReadLine)
wMain.myChart.hour16 = Val(buffer.ReadLine)
wMain.myChart.hour17 = Val(buffer.ReadLine)
wMain.myChart.hour18 = Val(buffer.ReadLine)
wMain.myChart.hour19 = Val(buffer.ReadLine)
wMain.myChart.hour20 = Val(buffer.ReadLine)
wMain.myChart.hour21 = Val(buffer.ReadLine)
wMain.myChart.hour22 = Val(buffer.ReadLine)
wMain.myChart.hour23 = Val(buffer.ReadLine)
wMain.myChart.hour24 = Val(buffer.ReadLine)

buffer.Close

end if[/code]

###############

code for app close event

[code] dim historyFile as folderItem
dim buffer as TextOutputStream

// create a file and a folder
historyFile = SpecialFolder.ApplicationData.Child(“inc.mycompany.myapp”).Child(“myapp_history”)

// Creates, or rewrites the preferences file
buffer = TextOutputStream.Create(historyFile)
buffer.WriteLine wMain.lBreakTime.Text
buffer.WriteLine “”
buffer.WriteLine “saved”
//buffer.WriteLine CStr(wMain.myChart.hour1)
//buffer.WriteLine CStr(wMain.myChart.hour2)
//buffer.WriteLine CStr(wMain.myChart.hour3)
//buffer.WriteLine CStr(wMain.myChart.hour4)
//buffer.WriteLine CStr(wMain.myChart.hour5)
//buffer.WriteLine CStr(wMain.myChart.hour6)
//buffer.WriteLine CStr(wMain.myChart.hour7)
//buffer.WriteLine CStr(wMain.myChart.hour8)
//buffer.WriteLine CStr(wMain.myChart.hour9)
//buffer.WriteLine CStr(wMain.myChart.hour10)
//buffer.WriteLine CStr(wMain.myChart.hour11)
//buffer.WriteLine CStr(wMain.myChart.hour12)
//buffer.WriteLine CStr(wMain.myChart.hour13)
//buffer.WriteLine CStr(wMain.myChart.hour14)
//buffer.WriteLine CStr(wMain.myChart.hour15)
//buffer.WriteLine CStr(wMain.myChart.hour16)
//buffer.WriteLine CStr(wMain.myChart.hour17)
//buffer.WriteLine CStr(wMain.myChart.hour18)
//buffer.WriteLine CStr(wMain.myChart.hour19)
//buffer.WriteLine CStr(wMain.myChart.hour20)
//buffer.WriteLine CStr(wMain.myChart.hour21)
//buffer.WriteLine CStr(wMain.myChart.hour22)
//buffer.WriteLine CStr(wMain.myChart.hour23)
//buffer.WriteLine CStr(wMain.myChart.hour24)
buffer.Close[/code]

Um all of your write lines after “saved” are commented out.

So it’s not saving anything to read.

You might try moving the code to the CancelClose method. Maybe myChart has been destroyed by the time you try to read it in Close. You also might try a more robust data system that won’t horribly fail if someone removes a line.

No no sorry,
The app I run was with active write lines.
I commented the lines to play with other methods, to find a way to fix it.
I forgot to uncomment the lines before posting them here.

[quote=117245:@Tim Parnell]So it’s not saving anything to read.

You might try moving the code to the CancelClose method. Maybe myChart has been destroyed by the time you try to read it in Close. You also might try a more robust data system that won’t horribly fail if someone removes a line.[/quote]

What can I do to prevent myChart from getting destroyed?

BTW, does replacing myChart properties with main app properties resolve the problem? I guess it does, but that’s not a neat idea.

It gets destroyed because the app is trying to close (where it destroys everything.)

Try moving the saving chunk to the Window.CancelClose to ensure that the container hasn’t been destroyed. The App.CancelClose might be too late.

[quote=117248:@Tim Parnell]It gets destroyed because the app is trying to close (where it destroys everything.)

Try moving the saving chunk to the Window.CancelClose to ensure that the container hasn’t been destroyed. The App.close might be too late.[/quote]
you meant app.close might be too late? was that a typo?

Okay let me try.
I guess making a custom method under app which first saves the data and then calls app.close would do the trick as well. but I don’t know how to connect the method to OSX window title bar red close button.

Event App.CancelClose - Your app is not affected yet, and you even have a chance to deny it quitting.
Event App.Close - App will close after this event anyway. Destruction is imminent.

Tested using CancelClose event.
Problems:
– when the file already exists, it gets rewritten almost correctly, only problem is the first line is removed and everything goes up one line.
– when I delete the file after the application starts and reads it. upon closing the app, a file with 24 zeros is created again…

I’m completely noob regarding databases.
But can you guide me how to start using an SQLite database instead of these damn headache giving text files?
I guess the learning curve will be steeper, but it will be more rewarding down the road.

Even better would be to get comfortable with the debugger and step through the code and find out what’s really going on. Otherwise you’re just masking the problem.

Then dump the text file and go with a database.

Write line:
buffer.WriteLine CStr(wMain.myChart.hour2)

Read Line:
wMain.myChart.hour14 = Val(buffer.ReadLine)

So, you save a CString and you read an integer ?

(I picked one read and one write line, this happens to be 2 and 14 and is not important).

You may split the line and check against errors, just in case one of the two (or the two) Childs are Nil or does not .Exists…

[quote=117242:@Radium Radiovich]myChart has 24 integer properties: hour1, hour2, … , hour24 for storing values for each hour.

The values are saved as a textfile in a subfolder inside Application Support.[/quote]
Don’t you have a design flawn here ?

You want to save integer properties in a Text File ?

Either save the values as string and read strings (with TextInputStream and TextOutputStream)

or store Integers and use BinaryStream to read / write.

There is no implicit conversion between Integer and String. You have instructions to do so in Xojo (Format, Str, Val, CdBL, etc.)

[quote=117290:@Emile Schwarz]Write line:
buffer.WriteLine CStr(wMain.myChart.hour2)

Read Line:
wMain.myChart.hour14 = Val(buffer.ReadLine)

So, you save a CString and you read an integer ?

(I picked one read and one write line, this happens to be 2 and 14 and is not important).[/quote]

All myChart hour properties are integer.
The values saved in textfile are strings.

So when reading from textfile, I used val() to convert string into integer to be stored in properties.

And when saving into textfile, I used CStr() to convert integer into string to be stored in textfile.

my opinion

a) Do not make myChart a property of wMAIN, make it global by using a module. remember Windows are closing during the app close event… and timing is never guaranteed.

b) make myChar.hourt and ARRAY instead of having 24 unique named instanced myChart.hour(24)

dim historyFile as folderItem
  dim buffer as TextInputStream
  dim i as integer
  // create a file and a folder
  historyFile = SpecialFolder.ApplicationData.Child("inc.mycompany.myapp").Child("myapp_history")
  
  // If available, reads the preferences file
  if historyFile.Exists then
    buffer = TextInputStream.Open(historyFile)
    wMain.lBreakTime.Text = buffer.ReadLine
    for i=1 to 24
       wMain.myChart.hour(i)= Val(buffer.ReadLine)
    next i
    buffer.Close
  end if
dim historyFile as folderItem
  dim buffer as TextOutputStream
  dim i as integer
  // create a file and a folder
  historyFile = SpecialFolder.ApplicationData.Child("inc.mycompany.myapp").Child("myapp_history")
  
  // Creates, or rewrites the preferences file
  buffer = TextOutputStream.Create(historyFile)
  buffer.WriteLine wMain.lBreakTime.Text
  buffer.WriteLine ""
  buffer.WriteLine "saved"
  for i=1 to 24
     buffer.WriteLine CStr(wMain.myChart.hour(i))
next i
  buffer.Close

The point of some of those comments is that CStr and Val may conflict with each other. CStr uses the user’s settings for the decimal mark, while Val expects only the US version (a period). Use CStr and Format for communicating with users; use Str and Val for communicating with machines.

Correction to last, CDbl and (CStr or Format).

CStr <> Cstring !

My error, sorry !