A Question of Variables and PLISTs

Hey folks,

Bit of a question and a quandary here for you folks, trying to get my head around this and feeling a bit at a loss, I’ve been through the scripting guide, I’ve been trawling through forums and I seem to get myself further in a tizzy so I come to ask my question here.

I’m trying to get some variables to persist through running, I’ve got some running through a PLIST but my quandary is coming towards locations, I’m trying to get a folder location that could be changed at short notice but also may not be changed for some time, my problem comes into storing the location, I was thinking to store it within a PLIST with the other items but I cannot get it to store within there, it’ll prompt to select the folder but when saving it I cannot find any record of it in the PLIST file.

So I’m wondering if any the more experienced folks here have any information or recommendations?

As ever I appreciate all of the help from you folks and the time you take to answer.

I save all my script preferences in “.dat” files saved as an AppleScript list.
Super easy to save and read back in.

I have a Script Library I made that has the getPrefs and setPrefs routine

here is the library. “ScriptPreferences.scpt”
You send it the name of the preference file you want. I use filenames that end with .dat like so “AppPreferences.dat”

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

on get_prefs(pFile as string)
	local cfile, show_list
	set cfile to (path to preferences as text) & "ScriptPrefs:" & pFile
	try
		set cfile to open for access cfile with write permission
	on error
		display alert "Uh-oh! Error opening file…" giving up after 10
		return false
	end try
	try
		set show_list to read cfile from 1 as list
	on error
		display alert "File Empty!" giving up after 5
		write {} to cfile as list
		set show_list to {}
	end try
	close access cfile
	return show_list
end get_prefs

on set_Prefs(pFile as string, pList as list)
	local cfile, flag
	set flag to false
	try
		set cfile to (path to preferences as text) & "ScriptPrefs:" --& "com.rmf.test.prefs"
		alias cfile
	on error eStr number eNum
		set flag to true
	end try
	if flag then
		try
			tell application "System Events"
				set cfile to path of (make new folder at end of (path to preferences) with properties {name:"ScriptPrefs"})
			end tell
		on error
			display alert "Uh-oh! Error creating folder \"ScriptPrefs\" in Preferences folder." giving up after 10
			return false
		end try
	end if
	set cfile to cfile & pFile
	try
		set cfile to open for access cfile with write permission
	on error eStr number eNum
		display alert "Uh-oh! Error opening file…" giving up after 10
		return false
	end try
	try
		set eof cfile to 0
		write pList to cfile as list
	on error
		display alert "Error! Can't write to preference file…" giving up after 10
	end try
	close access cfile
	return true
end set_Prefs

Robert has provided a fine solution.
If you need to use plists specifically then you can use these…

edit: universal path for easier testing.

--11/18/24 https://www.macscripter.net/u/paulskinner/
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

set dtp to (path to the desktop folder) as text
set fileObject to dtp & "plist.plist" --Path to the plist. It need not exist.
set theArray to {dtp} --Your path as text in a list.

FileSystem_Plist_Write(fileObject, theArray)
(item 1 of FileSystem_Plist_Read(fileObject)) as text --> "Macintosh HD:Users:paulskinner:Desktop:"




on FileSystem_Plist_Read(fileObject)
	try
		set fileObject to FileSystem_Object_As_Posix_Path(fileObject)
		set theData to current application's NSData's dataWithContentsOfFile:fileObject
		set theArray to current application's NSPropertyListSerialization's propertyListWithData:theData options:0 format:(missing value) |error|:(missing value) -- read file
		return theArray
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_Plist_Read>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_Plist_Read

on FileSystem_Plist_Write(fileObject, theArray)
	try
		set fileObject to my FileSystem_Object_As_Posix_Path(fileObject)
		set {theData, theError} to current application's NSPropertyListSerialization's dataWithPropertyList:theArray format:(current application's NSPropertyListBinaryFormat_v1_0) options:0 |error|:(reference)
		set theResult to theData's writeToFile:fileObject atomically:true -- write to file
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_Plist_Write>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_Plist_Write

on FileSystem_Object_As_Posix_Path(FileSystemObject)
	try
		try
			return POSIX path of FileSystemObject
		on error
			try
				tell application "System Events"
					return POSIX path of ((path of disk item (FileSystemObject as string)) as alias)
				end tell
			on error
				return POSIX path of (FileSystemObject as alias)
			end try
		end try
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Object_As_Posix_Path>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Object_As_Posix_Path

Like Paul, I use ASObjC to save a file/folder path to a plist file. If someone wants a simple solution, a text file can be used. BTW, I don’t believe an alias or file object can be saved in a plist file. It would have to be converted to either an NSURL or a POSIX or HFS path.

set theFolder to (choose folder) as text --just for testing

set settingsFile to POSIX path of (path to documents folder) & "Save Path.txt" --set to desired value

do shell script "echo " & theFolder & " > " & quoted form of settingsFile --save file path

--try --get saved file path
--	set savedFolder to paragraph 1 of (read POSIX file settingsFile as «class utf8»)
--on error
--	display dialog "The settings file was not found" buttons {"OK"} cancel button 1 default button 1
--end try

There’s a lengthy chapter in Shane’s ASObjC on saving preferences, but my needs are very simple, and the following has always worked for me. However, it does require the Foundation Framework, which some might prefer to avoid. Error correction needs to be added to deal with the situation where the plist file or key do not exist.

use framework "Foundation"
use scripting additions

--write and read a path in a plist
writePlist("AutoFolder", "/Users/peavine/Documents/Auto/") --parameters are key name and value
# set autoPath to readPlist("AutoFolder") --parameter is key name

--write and read another path in the same plist
# writePlist("MedicalFolder", "/Users/peavine/Documents/Medical/")
# set medicalPath to readPlist("MedicalFolder") --parameter is key name

on readPlist(theKey)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.Test"
	return theDefaults's objectForKey:theKey
end readPlist

on writePlist(theKey, theValue)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.Test"
	theDefaults's setObject:theValue forKey:theKey
end writePlist

A screenshot of the plist file:

1 Like

If I understand correctly, the author’s question is not about how to save and read a plist but rather where to store it.
I’ve tried using a specially designated folder for plist files in several locations. The locations that seem to be least problematic are:
In my home folder (eg ~/scriptPreferences), in the scripts folder where I keep all my Applescripts (eg ~/Documents/Scripts/scriptPreferences), in the Library (e.g. ~/Library/Preferences/scriptPreferences) or in the Library Scripts folder (~/Library/Scripts/scriptPreferences).
Whatever location is in use, I aways create the “scriptPreferences” folder, so that I know no other application will expect to use that folder.
I find it helpful to put a link to the “scriptPreferences” folder in the Finder’s Sidebar.

Hey folks,

Thank you all for the responses, I have been tinkering with all of these and learning from them all, ASObjC is still beyond my skill I will admit that as I’m trying to get my head round AS as a first step in the hope of improving and using Swift as well as ASObjC some day.

Out of all of them peavines was the simplest to implement with using POSIX files and reading them back, to answer the questions that seem to have been floating about, it was not about the PLIST itself, I wanted to prompt a dialog box that would ask for a folder location (Select where to look for and store files), then to store that within the PLIST for simplicity of saving data together, then reading back the location in later runs so I’m not prompted multiple times for where the file is or other info.