Writing the Record to plist file, then read it back

Hello,

I can write the record {aString:“Hello,word!”, anInteger:1, aReal:3.14} to the plist file this way:


{aString:"Hello,word!", anInteger:1, aReal:3.14} -- my test record

do shell script "defaults write my.domain myRecord -dict 'aString' 'Hello,word!' 'anInteger' '1' 'aReal' '3.14'"

My request for help is: how can I get my record back to my Apple-script, effectively?

Here is my attempt, which returns structured text instead of the record:

do shell script "defaults read my.domain myRecord"

the result is following:

“{
aReal = "3.14";
aString = "Hello,word!";
anInteger = 1;
}”

Note that the order of entries is different when reading and writing!!!

Also, following gives to me the type (dictionary in this case) of myRecord in the plist file:


do shell script "defaults read-type my.domain myRecord"
--> "Type is dictionary"

I got it! (with help from user @CK in the previous topic) :slight_smile:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set resultString to (do shell script "defaults read my.domain myRecord")

my (NSString's stringWithString:resultString)'s propertyList() as record

Now, I have other problem: I can indicate the Type of every Value when writing to plist file, but the snippet above returns all Values as string!!!


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

-- write
do shell script "defaults write my.domain myRecord -dict 'aString' -string 'Hello,word!' 'anInteger' -integer '1' 'aReal' -float '3.14'"
delay 1

-- read back
set resultString to (do shell script "defaults read my.domain myRecord")

my (NSString's stringWithString:resultString)'s propertyList() as record
--> {aReal:"3.14", aString:"Hello,word!", anInteger:"1"}

Is this my flaw or a flaw in AppeScriptObjC bridging? In any case, how to fix it, if possible?

The values are string because you write all values as string (which is the default).

To write specific types you have to add flags like -int and -float

do shell script "defaults write my.domain myRecord -dict 'aString' 'Hello,word!' 'anInteger' -int '1' 'aReal' -float -'3.14'"

An alternative to read the data is

set plist to do shell script "defaults read my.domain myRecord"
set plistData to my ((NSString's stringWithString:plist)'s dataUsingEncoding:4)
set theRecord to (current application's NSPropertyListSerialization's propertyListWithData:plistData options:0 format:(my NSPropertyListOpenStepFormat) |error|:(missing value)) as record

Edit:

I noticed that in both cases the values are still string when reading back the data even without coercing to record. I regard this as a bridging issue

Second edit:

This reads the data correctly

set plistPath to POSIX path of (path to library folder from user domain) & "Preferences/my.domain.plist"
set plistData to my (NSData's dataWithContentsOfFile:plistPath)
set plist to (my (NSPropertyListSerialization's propertyListWithData:plistData options:0 format:(my NSPropertyListXMLFormat_v1_0) |error|:(missing value)))
set theRecord to (plist's objectForKey:"myRecord") as record

No, I am writing correctly, and my entry matches yours (as I checked in BBEdit), you are just using the shortened form of option names.

Excellent! Thanks for the help, it works.

Now it remains to understand only one thing: how to force defaults command not to add garbage from RAM to the tail of a real number when converted to a float. :slight_smile:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

-- write
do shell script "defaults write my.domain myRecord -dict 'aString' -string 'Hello,word!' 'anInteger' -integer '1' 'aReal' -float '3.14'"
delay 1

-- read back
set plistPath to POSIX path of (path to library folder from user domain) & "Preferences/my.domain.plist"
set plistData to my (NSData's dataWithContentsOfFile:plistPath)
set plist to (my (NSPropertyListSerialization's propertyListWithData:plistData options:0 format:(my NSPropertyListXMLFormat_v1_0) |error|:(missing value)))
set theRecord to (plist's objectForKey:"myRecord") as record

--> {aString:"Hello,word!", aReal:3.140000104904, anInteger:1}

This is the normal imprecision of floating point numbers.

Please read Is floating point math broken? on Stackoverflow

It’s annoying.

Because this means: you have to write a real in text form, then after reading the value, convert it back to a real, and for the correct reverse conversion on remote computers, you will have to define a local setting for the decimal separator.