Help - Changes in Values of Properties are Not Remembered

I have been struggling with a weird quirk in AppleScript. Here is a test script:

property gg : "Hello Rob"
display dialog gg
set gg to "Goodbye"

If I run this script from the Script Editor, it works as expected. The first time it is run, it displays “Hello Rob” and any subsequent run it displays “Goodbye”.

But if I run this script from the Script Menu in iTunes, it does not work that way. Compile the script but do NOT run it and save it in ~/Library/iTunes/Scripts. EVERY time you run the script from the script menu in iTunes, it displays “Hello Rob”. Changes to the gg property are NOT remembered.

What is happening? Is there a way to use properties in a script that is called from the iTunes Script Menu where changes to the properties’ values are remembered between runs of the script?

Rob
P.S. I am using the latest version of Tiger.

Run repeatedly from the Script Editor or from an applet, the property is saved. Running from a script menu in an applications script menu recompiles the script every time so it takes the initial value every time.

Either save the script as an app (nuisance because you have to wait for it to start) or save the property yourself by writing it to a file and reading it back.

Note that it works fine when using the sytem’s Script Menu.

Thanks for the replies. Well starting with iTunes 7.3.2, scripts saved as apps CANNOT be launched from the iTunes Script Menu. (Only scripts can be launched from the iTunes Scripts menu). I do not know why Apple decided to limit the functionality of the iTunes Script Menu. Maybe it is a bug.

I also do not think that the script is recompiled every time. If you run my test script a couple of times from the Script Editor and then save it as a script into ~/Library/iTunes/Scripts, the script will display 'Goodbye" every time you run it. It appears that the value of the property when the script is saved is what iTunes uses. Very strange.

At this stage, it looks like I have three options:

  1. Wait until Apple fixes the bug and allows me to launch apps from the iTunes Script Menu.
  2. Run the Script oustide the iTunes Scripts Menu
  3. Save and load the properties to/from a file.

Option 3 looks like the best approach even though it is a lot more work.

Rob

Is the system Script Menu not an option? (See AppleScript Utility.app in Tiger.)

http://www.apple.com/applescript/scriptmenu/01.html

Here’s some subroutines I have to help with reading, writing, and deleting things from plist files. I hope they help.

(*this shows how to use the defaults subsystem to read, write, and delete key value pairs in preference files*)
(* the plist file is written in binary format... to convert it to text: do shell script "plutil -convert xml1 " & prefsFilePath & ".plist" *)

(*
keyType values can be:
string
data ==> the data must be in hexadecimal
integer ==> a number
float ==> a floating point number
boolean ==> true,false,yes,no
date ==> a date value
array ==> an array in the form defaults write somedomain preferencekeyP -array element1 element2 element3
dict ==> a new dictionary in the form defaults write somedomain preferencekeyP -dict keyP1 value1 keyP2 value2
*)


property prefFolderLocation : path to preferences folder from user domain as Unicode text
property prefFileName : "testPlist"
property prefsFilePath : prefFolderLocation & prefFileName
property keyName : "aString"
property keyType : "string"

set keyValue to "Hello Rob"
writeDefault(prefsFilePath, keyName, keyType, keyValue)
set gg to readDefault(prefsFilePath, keyName)
display dialog "This should be \"Hello Rob\"" & return & return & "The value is: " & gg

delay 0.5

set keyValue to "Goodbye"
writeDefault(prefsFilePath, keyName, keyType, keyValue)
set gg to readDefault(prefsFilePath, keyName)
display dialog "This should be \"Goodbye\"" & return & return & "The value is: " & gg


(*========== Subroutines ===========*)
on writeDefault(prefsFilePath, keyName, keyType, keyValue)
	set keyType to ("-" & keyType) as Unicode text
	if prefsFilePath contains "/" then
		do shell script "defaults write " & quoted form of prefsFilePath & space & quoted form of keyName & space & quoted form of keyType & space & quoted form of keyValue
	else
		do shell script "defaults write " & quoted form of POSIX path of prefsFilePath & space & quoted form of keyName & space & quoted form of keyType & space & quoted form of keyValue
	end if
end writeDefault

on readDefault(prefsFilePath, keyName)
	if prefsFilePath contains "/" then
		do shell script "defaults read " & quoted form of prefsFilePath & space & quoted form of keyName
	else
		do shell script "defaults read " & quoted form of POSIX path of prefsFilePath & space & quoted form of keyName
	end if
end readDefault

on deleteDefault(prefsFilePath, keyName)
	if prefsFilePath contains "/" then
		do shell script "defaults delete " & quoted form of prefsFilePath & space & quoted form of keyName
	else
		do shell script "defaults delete " & quoted form of POSIX path of prefsFilePath & space & quoted form of keyName
	end if
end deleteDefault

Side note: Your write handler is better, but I would consider using something like this so you don’t have to pass the filename every time:

script userDefaults
	property _domain : quoted form of "Test" -- quoted form of either a "domain" or POSIX path
	
	on readKey(_key, _defaultValue)
		try
			do shell script "/usr/bin/defaults read " & _domain & space & quoted form of _key
		on error
			return _defaultValue
		end try
	end readKey
	
	on writeKey(_key, _value)
		do shell script "/usr/bin/defaults write " & _domain & space & quoted form of _key & space & quoted form of _value
	end writeKey
end script

-- Example
repeat
	tell userDefaults to readKey("Test", "New value")
	display dialog ("Current value: " & result) default answer ""
	tell userDefaults to writeKey("Test", text returned of result)
end repeat

In my script the file was specified as a global variable, so it didn’t need to be passed anyway, but those subroutines were written for the general case. If he knows exactly the form he’s using in a particular script then of course they can be tailored for the specific case, so why stop with just not passing the file?

In this specific case we know several things…

  1. properties are global values so we don’t need to pass any of them
  2. the default keyType is string so it doesn’t even need to be declared at all
  3. the default path to save the preference file is the user’s preferences folder, so we don’t need to specify a path.
  4. the prefFileName is one word so it doesn’t need to be quoted
  5. the keyName is one word so it doesn’t need to be quoted
  6. the value will be in the plist file so we don’t need to error check during the read

As such, the script for this specific case could be written as follows if that’s what you want to do. By the way, I liked your error checking in the “read” subroutine and the way you defined the path to the defaults command… I’ve implemeted those fixes into my script library.

property prefFileName : "testPlist"
property keyName : "aString"

writeDefault("Hello Rob")
repeat
	display dialog "Current Value: " & (readDefault()) default answer ""
	writeDefault(text returned of result)
end repeat

on writeDefault(keyValue)
	do shell script "/usr/bin/defaults write " & prefFileName & space & keyName & space & quoted form of keyValue
end writeDefault

on readDefault()
	do shell script "/usr/bin/defaults read " & prefFileName & space & keyName
end readDefault

Thanks for all the replies. And yes Bruce using the System Script Menu is an option. I apologize for omitting it from my list of options.

Ii have also been trying to use another option but I can’t get it to work. Save the script as a Application and then create another script to launch this application.

e.g.

run application “ABCD”

And then place this script in the iTunes Script Menu. (Since iTunes 7.3.2, only Compiled Scripts show up in this menu).

But I can’t get it to work. Running this mini script in the Script Editor generates an error – “Connection is invalid”. But when i run this one line script from the iTunes Script Menu, I get the Beach Ball and it crashes iTunes.

Rob

I am also going to try writing and reading to a pref File. I like the routines suggested. Many Thanks.

But I have one question. Will the routines suggested work with Unicode text? Some of my properties contain Unicode Text.

Rob

Not quite. When I try to read “植松伸夫” I get back “\u690d\u677e\u4f38\u592b”.