Guys,
I have an app which has a preferences section. The preferences( Property, Value) are displayed in a table view from a CUSTOM plist file. A user can double click a table row which then populates two textfields ‘Property’ and ‘Value’ respectively. A user can then update the value for a particular property and submit it.
After successful write to the plist file, the preferences are updated and displayed in a table. The issue is that every now and then I get an error when updating the plist file. Here is the code that updates the plist file:
on updateP_(sender)
set pval to theVal as string
set pkey to theProperty as string
// theVal and theProperty are the text field bindings for the Value and Property textfields
try
do shell script "defaults write " & quoted form of plistFile & " " & quoted form of pkey & " " & quoted form of pval
set updatedPref to {theProperty:pkey, theVal:pval}
theDataSource's replaceObjectAtIndex_withObject_(doubleClickedSelectedRow as integer, updatedPref)
aTableView's reloadData()
on error errorMessage
display dialog errorMessage
end try
end updateP_
The code above works fine in some cases. But when I tried to submit a value “[Test String]” for a property, I got the following error:
Shouldn’t
quoted form of
take care of the quoting issue? Are the characters ‘[’ and ‘]’ the real issue?
I don’t know about “quoted form of”, but why are you using a shell script to write your preferences instead of using NSUserDefaults?
I’m relatively new to Applescript and Xcode and still learning the ropes. I didn’t know about NSUserDefaults. I have been using shell script to write to plist files and it has always worked for me until I hit this road block.
The plist file is created by my app automatically for every user when the app is run the first time
You should have a look at the NSUserDefaults Class Reference in the docs. There is a method, registerDefaults which essentially set the “factory defaults” which show up the first time an app is run, and then the user can change those with setValueForKey, and then those new defaults will show up until they’re changed. You can also bind the values of a text field to the Shared User Defaults Controller in IB, which I think will do what you want with no code at all.
Ric
THis turned out to be a quoting issue in bash. Here is the solution that worked:
do shell script "defaults write " & quoted form of plistFile & " '" & pkey & "' " & " '\"" & pval & "\"' "
Still, NSUserDefaults is way more easier and does a lot of the work for you. Also, in 10.7, the Preferences folder is now owned by the OS, which means your script may not work anymore. NSUserDefaults will be the only way. Here’s a start. Put this in your app delegate:
First you need to define a property to the user defaults before using it:
set theDefaultManager to current application's NSFileManager's defaultManager()
This goes in the applicationWillFinishLaunching_ method:
on registerAppDefaults_(sender)
try
tell userDefaults
registerDefaults_({preferenceOne:"value", preferenceOne:"value"})
end tell
on error theError number theErrorNumber
log ("registerAppDefaults_ : " & theErrorNumber & " : " & theError) as string
end try
end registerAppDefaults_
To read them back in, again in the applicationWillFinishLaunching_ method:
on readDefaults_(sender)
tell userDefaults to set preferenceOne to (stringForKey_("preferenceOne")) as string
end readDefaults_
And to save them when you app terminates you put this in the applicationShouldTerminate_ method:
on saveAppDefaults_(sender)
tell userDefaults to setObject_forKey_(preferenceOne, "preferenceOne")
tell userDefaults to |synchronize|()
end saveAppDefaults_
Plus you could also save the entire contents of the table view in the preferences by using bindings in IB. No code, just binding the contents of the array controller with Shared User Defaults and assigning a path key to the name you’d like the preferences to be saved, and all is done automatically.
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
I noticed that in your examples, the property theDefaultManager was not used. When I use NSUserDefaults I use
property userDefaults : class "User Defaults" of current application
and then I use your script.
???
Sorry, made a mistake. It should have been this instead:
tell current application's NSUserDefaults to set userDefaults to standardUserDefaults()
and that goes in the applicationWillFinishLaunching_ method, before the registerAppDefaults_ and readDefaults_ of course. userDefaults is defined as a global property on top, anywhere after property parent : class “NSObject”.
But I guess your way could work too, haven’t tried it. I kinda remember havin’ seen it used like that before, but not 100% sure… but hey, I guess it doesn’t hurt to try!
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
and that should be
property userDefaults : class "NSUserDefaults" of current application
for it to work. You’re accessing a cocoa framework, gotta use the correct spelling.
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
property userDefaults : class "NSUserDefaults" of current application
That is what it should be.
Sorry about that.
I just found by accident what I saw long ago:
http://developer.apple.com/library/mac/#releasenotes/ScriptingAutomation/RN-AppleScriptObjC/_index.html
At the end, last section:
property NSColor: class "NSColor"
property NSCalibratedRGBColorSpace: my NSCalibratedRGBColorSpace
script MyView
property parent: class "NSView"
on drawRect_(rect)
set c to NSColor's whiteColor()
c's colorUsingColorSpaceName_(NSCalibratedRGBColorSpace)
end drawRect_ --fixed Apple's mistake, was end convert_ ?!?
end script
so no “of current application” it seems. Untested though…
Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)
The problem comes when you actually try to compile such a thing…