User is having trouble reading preferences files

One of my users is on Monterey and I’ve tested my app to work properly up to Ventura, but for some reason his computer will not let the app read files from Library/Preferences or Application Support. These are plain text files created natively by the app. Never had this problem before.

I see FileVault is turned on by default in Ventura (i turned mine off). Would this interfere with reading the files if it’s turned on? I’m guessing it’s turned on by default in Monterey as well.

What is the code? What error do you get? Did the user restart his computer?

I have had a few cases of users not having access to their own Application Support folder. A restart usually fixes this. The Preferences file should be a plist and not a plain text file.

A couple of things about this path.

  1. I assume you mean ~/Library/Preferences, because Library/Preferences shouldn’t be writable in the first place. This is a system location and typically requires privilege escalation to access from a user space application.

  2. Since Mac OS X 10.9 Apple have been advising against manually reading and writing to the User preferences folder (~/Library/Preferences). You are supposed to use the Apple preferences system that they introduced in Mac OS X 10.0. Check out the 11 year feedback report requesting this functionality https://tracker.xojo.com/xojoinc/xojo/-/issues/18346. If you have a copy of the now discontinued Ohanaware App Kit, it includes code to access NSUserDefaults. If not, I’m sure a MVP can sell you a plugin for it.

The application support folder is also one of the area where Apple have guidelines on how to use. Make sure that the subfolder your application creates is the BundleID of the application “~/Library/Application Support/com.ohanaware.appWrapper4RG2”.

Thanks for all the suggestions. This is what happens when an old art major learns to code. I see how things SHOULD be, but if 2 computers are using the same app on the same OSX version, how could it work on one and not the other? That does not seem logical to me.

Welcome to my world :slight_smile:

You basically need more information as to what might be causing this problem.

If it were me, I’d start by ensuring that you’re accessing the correct paths. They MUST point to the User data and in the case the preferences folder, do not try to use it in the way you are. Either learn how to use declares to access the Apple preferences system or write your prefs file into the Application Support folder (the users one, not the system one).

Next I’d write code to create an error message if it fails, one of the things I’d check is the permissions on the file (if it exists) or permissions on the folder if the file doesn’t exist.

Think about (and ask the community) things that can be different and how to test for them when things fail. The more information you can gather, the higher possibility you can relay a helpful error message that can either help your customer directly solve the issue or provide information to you to help you understand the error.

1 Like

FWIW, regardless of Apple’s choices, all my apps write their prefs in a free binary format inside ~/Library/Preferences and without issue.

I’ve been doing it this way since 2007 and never had an issue until now. You would think Apple would have flagged that when I submitted to the MAS, but it’s been available there for years with several updates.

I have error codes but they only tell me that those files could not be opened for some reason. I had the user check the file permissions and they are Read & Write like mine are. Can it be, though, that if he doesn’t have admin privileges it won’t work? If so I can’t believe I haven’t had this issue years ago.

The MAS check is done in about 10-15 minutes. What do you think that Apple’s minions do in that time?

Let the user delete the file, log out and log back in. Then the user can try again.

It is entirely up to you guys what you do with your apps, I am merely pointing out that you’re going against Apple’s guidelines. They’re only guidelines, until someone at Apple decides to make 'em rules.

On the plus side, Apple’s NSUserDefaults is really easy to use in your application as it is basically a dictionary, you simply set or read whatever you want and let Apple handle how the data is stored to disk.

Yes, I was not implying you were wrong; just that I won’t agree with Apple’s choice.

Granted. I feel more comfortable with writing classes serially in a binary stream.

The user has tried on several Macs at his business with the same results, so I’m doubting it’s a matter of restarting or logging in again. Wondering if their IT department has something preventing proper permissions. He said they don’t, but it does seem odd. I also tried creating another user on my Ventura machine that had standard permissions (not admin) and it ran fine there too, but it was installed using admin account. Maybe I could delete it and try reinstalling from the test account.

Thanks for all the suggestions. I will try to rewrite how preferences are accessed. I’m not familiar with declares, though. Are there any good tutorials available you can recommend? Sample code?

Can you share a small and simple functional sample of what you are doing exactly, specially exposing the reproducible and offending part? Sometimes people do things exotically and other people can find something and offer a solution.

I think we’re going to need to know this to go forwards, is the problem when you read the text file IOException? If so, what’s the error code?

f = specialFolder.ApplicationData.child(“MyApp”).child(“MyApp”)

if f.exists then
t = f.openAsTextFile
if t <> nil then

/// some fun stuff goes on here…

end if
else

//// write default settings into preferences file

end if

Did he get sandboxed / translocated?

Not sure what you mean, Tim.

I had a msgbox saying “The file could not be opened for some reason.” I omitted that from my code.

I’m presuming that t is a textinputstream. Wouldn’t you also have a string property and do something like this?

f = specialFolder.ApplicationData.child(“MyApp”).child(“MyApp”)

if f.exists then
t = f.openAsTextFile
s=t.ReadAll
t.Close

//Do stuff with s

Not sure why you’re testing t for nil. It shouldn’t be if f is okay.

I think i got the if t <> nil from someone else’s code at the time. I didn’t understand it either.

Here is how I’m reading in the data in the getPrefs method. Each line in the file represents some data point saved in the preferences window of the app then written to the preferences file by a savePrefs method…

    txtFont = t.readLine
    txtSize = t.readLine
    txtStyle = t.readLine
    txtColor = t.readLine
    // ad nauseam
t.close

These values are then sent to the preferences window and the interface settings.

You can check by yourself. Using the IsReadable, IsWriteable, Permissions, Owner and Group properties of the folderitem, you can see whether your file or its parent folder has permissions you wouldn’t expect. You could then warn the user with a dialog, telling the exact cause.

There are two issues with that code:
• You don’t check if f=nil. When ApplicationData.child(“MyApp”) doesn’t exist, f will be nil in this code (and “if f.exists then” will raise a NilObjectException).
• If, for whatever reason (mostly permissions issues), ApplicationData.child(“MyApp”) isn’t accessible, your long line assigning to f will raise an exception. It’s usually better to split the line:
f=specialFolder.ApplicationData
if f<>nil and f.Exists then f=f.child(“MyApp”)
if f<>nil and f.Exists then f=f.child(“MyApp”)

(you might remove the “f.exists” intermediate calls, as a non-existent folder would turn f to nil; just always check for f<>nil; and check f.exists for the final file).

In the past, there used to be less exceptions raised, and checking whether the stream was nil was a catch-all solution.