Properties not being saved

I have this sample script, copied from elsewhere here in the Script Debugger 8 forum.

use AppleScript version “2.4” – Yosemite (10.10) or later
use scripting additions

property theRunCount : 0

set theRunCount to theRunCount + 1
display dialog “This script has been run " & theRunCount & " time(s).”

I created a new Script Debugger document and pasted that script in. When I click the Run button it shows “This script has been run 1 time(s).” When I click the Run button a second time I am expecting the message to say “This script has been run 2 times(s).” But it doesn’t. No matter how many times I click the Run button it always says “This script has been run 1 time(s).”

But… if I copy the contents of that Script Debugger 8 window, and paste it into a new Script Editor window, the counter does go up by 1 every time I click Run there.

Neither of these scripts have been saved. They are just new Script Debugger and Script Editor documents.

Looking around here in the forum and in the Help for Script Debugger it seems the key is a feature in Script Debugger called “Persistent Properties.” But… first of all, I can’t find that option (supposedly in the Scripts menu according to Script Debugger’s help, but not in my copy of SD 8.0.3), and second of all, the help entry in SD 8 is talking about choosing Script > Persistent Properties when saving a script, and I have not saved these scripts yet at all.

If I do save the scripts (as applications) the one saved from Script Debugger 8 always shows “This script has been run 1 time(s).” The one saved from Script Editor always shows whatever the number was when I saved it (in my case, it’s “This script has been run 3 time(s).” because I’d clicked Run a few times before saving it).

I know that I don’t know enough about Properties but I know enough to know this is not how Properties are supposed to work!

This is with macOS 13.2.1.

If I take those two scripts (saved as applications) to another Mac running 10.13.6, the message in the dialog box increases by 1 every time I double-click either app (that is, the one saved with Script Debugger 8 works, and the one saved with Script Editor works). I don’t have Script Debugger 8 installed on that Mac but I do have SD 6 (which has a Script > Persistent Properties menu item) and in SD 6 the script does increment when run from the editor.

So… I sort of think this has to do with macOS 13.2.1.

If Properties don’t work properly in macOS 13 it’s going to be a big mess for me! Hoping that there’s a way to make things work. THANK YOU…

Properties are not reliably saved with scripts in recent versions of macOS. Shane explains this in the article that can be found here

So properties will not persist in universal applets run under Big Sur. If you need to store values between launches, you will have to do it yourself. This is a big change in long-standing AppleScript applet behavior, one you should consider carefully when updating scripts.

Two alternatives that can be used are text files and plists. Another alternative is Shane’s PrefsStoragLib script library which can be found here

1 Like

This is the solution I use, and I’ve written a script that makes it seemless to adapt an old script with a lot of properties:

set saveTID to AppleScript's text item delimiters

set myText to GetScriptText(1)
set keysAndValues to {}
set AppleScript's text item delimiters to {" : "}
set x to 0
repeat with thisGraph in myText
   set x to x + 1
   set thisGraph to thisGraph as text
   try
      copy word 1 of thisGraph to paraLead
      if paraLead is "property" then
         set lastPropertyLine to x
         set thisKey to word 2 of thisGraph
         set keyValue to the rest of text items of thisGraph as text
         set the end of keysAndValues to {thisKey, keyValue}
      end if
   end try
end repeat
set AppleScript's text item delimiters to {""}

set defaultValues to {"{"}
set valuesForKeyLines to {}
set savingValueLines to {}
set backupWriteCalls to {}
set keyValueCount to count of keysAndValues
repeat with x from 1 to keyValueCount
   set thisKey to item x of keysAndValues
   set {keyName, keyValue} to thisKey
   if x = keyValueCount then
      set the end of defaultValues to {keyName, ":", "{}"} as text
   else
      set the end of defaultValues to {keyName, ":", "{}, "} as text
   end if
   
   set the end of valuesForKeyLines to "   set my " & keyName & " to value for key \"" & keyName & "\""
   set the end of savingValueLines to "   assign value " & keyName & " to key \"" & keyName & "\""
end repeat

set the end of defaultValues to "}"
set AppleScript's text item delimiters to {" "}
set defaultValues to defaultValues as text
set AppleScript's text item delimiters to {""}

set storagePrepCall to {"prepare storage for (path to me) default values ", defaultValues, return, ¬
   "--prepare storage for domain \"com.edstockly.uniqueID\"  ", return, ¬
   "my RetreiveStoredValues()"} as text

set AppleScript's text item delimiters to {return}

set PersistentVariableHandler to {"on PersistentVariables()", ¬
   storagePrepCall, ¬
   "end PersistentVariables"} as text

set SaveVariablesHandler to {"on StorePersistentValues()", ¬
   savingValueLines, ¬
   "end StorePersistentValues"} as text

set RetreiveVariableHandler to {"on RetreiveStoredValues()", ¬
   valuesForKeyLines, ¬
   "end RetreiveStoredValues"} as text

set persistentVariableCalls to {{""}, ¬
   {"PersistentVariables()"}, ¬
   {"--StorePersistentValues()"}, ¬
   {"--RetreiveStoredValues()"}, ¬
   {""}}

set item lastPropertyLine of myText to {item lastPropertyLine of myText, persistentVariableCalls}

set the end of myText to {¬
   PersistentVariableHandler, "", ¬
   SaveVariablesHandler, "", ¬
   RetreiveVariableHandler, ""}
set myText to myText as text

set myText to FindChange(myText, "√¬√", "¬" & return)
set the clipboard to myText




--displayAlert 
set resultAlertreply to display alert ("Paste in persistent variables") ¬
   message ("The Clipboard contains the entire script with persistant variable handlers" & return & return & "You may paste it into your script.") ¬
   as informational ¬
   buttons {"OK"} ¬
   default button 1 ¬
   giving up after 30
--displayAlert 
return myText as text


on FindChange(textToSearch, textToFind, textToReplace)
   set saveTID to AppleScript's text item delimiters
   set AppleScript's text item delimiters to textToFind
   set textToSearch to every text item of textToSearch
   set AppleScript's text item delimiters to textToReplace
   set textToSearch to textToSearch as string
   set AppleScript's text item delimiters to saveTID
   return textToSearch
end FindChange

on GetScriptText(DocNumber)
   --tell application "TextWrangler" to set myText to text of window 1
   tell application "Script Debugger"
      tell its document DocNumber
         set myText to its source text
      end tell
   end tell
   
   set myText to paragraphs of myText
   set the beginning of myText to ""
   set AppleScript's text item delimiters to {return}
   set myText to myText as text
   set myText to FindChange(myText, "¬" & return, "√¬√")
   set textHeader to {}
   
   if return & "use scripting additions" is not in myText then
      set the end of textHeader to "use scripting additions"
   end if
   if return & "use script \"PrefsStorageLib\"" is not in myText then
      set the end of textHeader to "use script \"PrefsStorageLib\" version \"1.1.0\""
   end if
   set myText to (textHeader as text) & myText
   set myText to paragraphs of myText
   return myText
end GetScriptText

The idea is it will set up storage for all the properties in your script, build the handlers to store and retrieve them, and drop the handler calls at the top of your script.

After that, just make sure you include the
StorePersistentValues()
before your script ends.

(Edit: fixed the broken post)

FWIW, the following is a plist-equivalent of the script included by @christianboyce in post 1. This script works if it is run from within a script editor or as a saved script/app.

use framework "Foundation"
use scripting additions

set savedNumber to readPlist("CurrentNumberKey") -- read plist
if savedNumber is missing value then set savedNumber to 0 -- if plist not found
set newNumber to (savedNumber as integer) + 1
display dialog (newNumber as text)
writePlist("CurrentNumberKey", newNumber) -- write number to plist

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

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

BTW, the following is from the AppleScript Language Guide:

After you define a property, you can change its value with the copy or set command.

The value set by a property definition is not reset each time the script is run; instead, it persists until the script is recompiled.

So, it would seem that theRunCount should be incremented if the following script is run repeatedly in Script Debugger but it’s not (which may be the point being made by the OP). Perhaps Script Debugger recompiles the script every time it’s run.

property theRunCount : 0
set theRunCount to theRunCount + 1
display dialog "This script has been run " & theRunCount & " time(s)."

See this from Mark…

1 Like

Thanks Ed–that explains everything.

Thanks everyone for the answers. Somehow I missed (or forgot) that properties are not to be used any longer. We have other ways, so I’ll just start using another way. Hopefully I don’t have some old script somewhere using properties, just waiting to break…