Search code examples
c++macosqtqsettings

QSettings weird behaviour on MacOS


Using Qt 5.11.1 via homebrew on MacOS 10.13.6, I'm using QSettings in my application. This is a working program that I'm porting from Linux and Windows now to MacOS.

The issue I'm having on MacOS is that it'll save the file to /Users/michaelleonetti/Library/Preferences/com.sonarcloud.Sonarcloud Service.plist, which it's supposed to, on first program execution.

If I delete the file sometimes it comes back. Sometimes it doesn't. If I edit the plist file with Xcode and save it, the values I write in "have" won't be there.

I can't identify a rhyme or a reason to make it work.

I've created a minimal example:

#include <QSettings>

#include <iostream>

int main( int argc, char *argv[] )
{

    { // Scope
        QSettings settings( QSettings::NativeFormat, QSettings::UserScope, "My Application Company", "My Application" );
        if( settings.contains( "have" ) )
            std::cout << "We have: " << settings.value( "have" ).toString().toStdString() << std::endl;
        else
            std::cout << "You do not have" << std::endl;

        settings.setValue( "version", 10 );
        std::cout << "Path is: " << settings.fileName().toStdString() << std::endl;
    }

    return( EXIT_SUCCESS );
}

Output:

$ ./src/reproduce
You do not have
Path is: /Users/michaelleonetti/Library/Preferences/com.my-application-company.My Application.plist

File check

$ cat "/Users/michaelleonetti/Library/Preferences/com.my-application-company.My Application.plist"
cat: /Users/michaelleonetti/Library/Preferences/com.my-application-company.My Application.plist: No such file or directory

How can I get this issue solved?


Solution

  • I think this is due to QSettings being implemented on top of Apple's CFPreferences database. This is expected behavior and the "fix" is to call CFPreferencesSynchronize()

    Docs:

    writes all pending changes to preference data to permanent storage, and reads latest preference data from permanent storage

    Luckily it appears that QT wraps this in its Mac implementation for QSettings and you should be able to call QSettings::sync() to do this in a platform agnostic way.

    Basically you need to synchronize your settings before you will see any changes from external writes**. This is also why the file doesn't appear to always be rewritten (it should on application exit when things are automatically flushed).

    Note that you will also need synchronize your settings from the external application by calling CFPreferencesSynchronize() within that application in order to see changes made by your QT app.

    It also might be interesting to know that there is a command line utility available called defaults that you can use to perform syncronized writes from a shell script or terminal.

    ** This occurs naturally at certain points automatically.