f = SpecialFolder.ApplicationData.Child("My App Name").child("Printer Settings")
You cannot test if the first Child (My App) is Nil, Exists, etc.
And your names are too common to be used; that is why people avice to use com.companyname as a folder name; after, you do what you want (and get crash now, or your customers get some…)
OK, between the tips here and re-reading the documentation 100 times, the following code now successfully writes my printer settings to a prefs file located in the user’s Documents folder, in a subdirectory called LabelPrint (my app name).
Var pageSetup As PrinterSetup
pageSetup = New PrinterSetup
If pageSetup.ShowPageSetupDialog Then
App.s = pageSetup.Settings
End If
// save printer settings to file
Var f As FolderItem
Var bs As BinaryStream
// create folder for my prefs inside the user's Documents folder
Var myData As FolderItem = SpecialFolder.Documents.Child("LabelPrint")
if myData.Exists Then
// get a folderitem
f = SpecialFolder.Documents.Child("LabelPrint").child("Printer Settings")
// create a binary file with the type of text (defined in the file types dialog)
bs = BinaryStream.Create(f, True)
// check to see if it was created
If bs <> Nil Then
//write the contents of the editField
bs.Write(App.s.ConvertEncoding(Encodings.UTF8))
// close the binaryStream
bs.Close
End If
Else
myData.CreateFolder
End If
I can now successfully read the prefs from this location at application launch. Whew!
That’s going to fail to save the settings the first time, when myData does not exist. Better to get myData check Not Exists and create the folder. Then your following code to save the settings will run every time.
// create folder for my prefs inside the user's Documents folder
Var myData As FolderItem = SpecialFolder.Documents.Child("LabelPrint")
if not myData.Exists then myData.CreateFolder
// get a folderitem
f = SpecialFolder.Documents.Child("LabelPrint").child("Printer Settings")
// create a binary file with the type of text (defined in the file types dialog)
bs = BinaryStream.Create(f, True)
etc.
Your logic is faulty. The first time it runs it will create the LablePrint folder, but it won’t do anything else. You should look at @Tim_Hare 's post or my post (upthread) of yesterday.
Looking at everything sequentially, one might list the steps as follows:
The app starts and has NO IDEA what state the machine might be in. Well, I guess it knows that no one has unplugged the CPU , at least.
Here a miracle occurs
Now the app knows everthing is just peachy and can go merrily on doing its thing.
What we’re after is step 2. Breaking that down into smaller steps is the thing.
If we assume that the Documents folders is there [1], then the first step is whether LabelPrint exists. As @Tim_Hare 's post has it, check and create if not.
Next step is whether the Printer Settings file exists or not. If not create it with the user’s settings (for example)
You might also be creating a general Settings file with default settings if it doesn’t exist. If it does then you might feel you want to validate it. Or leave that as a future improvement, perhaps.
and so on. At each of these steps you check and then might or might not take an action, depending.
[1] Is checking that the Documents folder exists akin to checking that the CPU is plugged in? Not sure.
Plus, especially on macOS, your app needs permission to write to the user’s Documents folder. Before your app is able to write, macOS will ask the user for permission. Which is probably confusing to the user. As written above, better to use Specialfolder.Applicationdata.child(“reverse URL of your app”)
Whew. What a great community! It turns out my code did break as mentioned by Tim and Tim – I inadvertently already had the directory created, so it worked for me… until I went back, removed it, tested and saw the failure. And some of the suggested code I already had… but in the wrong place.
Here’s my corrected code, which seems to work in all test conditions now. One block below is in my app’s Opening Event Handler, while the other code is under my Page Setup menu option.
Event Handler - Opening
// read printer preference settings from file
Var f As FolderItem
Var bs As BinaryStream
// create folder for my prefs inside the user's Documents folder
Var myData As FolderItem = SpecialFolder.Documents.Child("LabelPrint")
if not myData.Exists then myData.CreateFolder
// get a folderitem
f = SpecialFolder.Documents.Child("LabelPrint").child("Printer Settings")
// make sure it exists before we try to read it
If f.Exists Then
// open the folderitem as a binary file without write privelages
// To open with write priviledges, use true instead of false
bs = BinaryStream.Open(f, False)
// make sure we have a binary stream to read from
If bs <> Nil Then
// read the whole binaryStream
App.s = bs.Read(bs.Length, Encodings.UTF8)
// close the binaryStream
bs.Close
End If
End If
and my creation of the Preferences file under my Page Setup menu handler:
Var pageSetup As PrinterSetup
pageSetup = New PrinterSetup
If pageSetup.ShowPageSetupDialog Then
App.s = pageSetup.Settings
End If
// save printer settings to file
Var f As FolderItem
Var bs As BinaryStream
// get a folderitem
f = SpecialFolder.Documents.Child("LabelPrint").child("Printer Settings")
// create a binary file with the type of text (defined in the file types dialog)
bs = BinaryStream.Create(f, True)
// check to see if it was created
If bs <> Nil Then
//write the contents of the editField
bs.Write(App.s.ConvertEncoding(Encodings.UTF8))
// close the binaryStream
bs.Close
End If
If you store a globalproperty (in the App.Open Event where you create the main folder for storing your application data), you will not need to do that line (with two Childs… Error prone).
You can also create a second global Property to store the printer settings folder reference and skip this line completely, but do not forget to test if these properties are Nil and Exists before continuing when (if) you will be there (went this road).
I see that you have a couple of options from here to answer your query. I just wanted to add that I picked up a module called ModernPreferences that works really well for me, mainly because it does most of the work for me; it saves and reads preferences in ~/Library/Application Support/[app name]. I’m sorry that I can’t credit the author but the code doesn’t have a name and I can’t remember where I got it from. However for what it’s worth I’ve attached the zip file that I originally downloaded. I hope you find it useful. xojo-modern-preferences-master.zip (8.5 KB)
I’m amazed that nobody has pointed out that Preferences on Mac typically go in the Preferences Folder. This is accessed by SpecialFolder.Preferences.
Now on macOS you have to access it via the NSUserDefaults or CFPreferences APIs. This is because it is cached by the system. I’m pretty sure MacOSLib has both as part of it. I have an NSUserDefaults module somewhere I could make available.