I am not sure if I am just totally new to NSPathControl and/or if the user defaults / preference file functionality has changed in some weird way that I missed.
I want to have a path control on a window that, when a path is selected, it writes that to a preference. I have used the user defaults feature before and it still works with a label for me so I don’t think things have changed. I have the PathCell value bound to the Shared User Defaults Control. It seems when the user selects a value for that it creates a preference file and writes stuff into the plist.
However, when I try setting the default when the app launches, no preference file is created and the preference is not written. Also, if I delete the preference file, the app continues to retain all the bound values as if the preference file was still there… not sure where those are coming from.
Help!
The applicationWillFinishLaunching contains
set recDefaults to {apSXPathToWatch:"Macintosh HD:Users:mark_munro:Desktop:TEST:"}
set defaults to current application's NSUserDefaults's standardUserDefaults()
defaults's registerDefaults_(recDefaults)
I have toyed with converting the path to a URL which seems to be what the path control wants to have but get all sorts of errors. The code above executes but simply does nothing.
Does anyone have any good example of interactions with an NSPathControl, preferably where the values are stored in User Defaults?
I tried POSIX and HFS paths and one other (fileURL or something or other)… problems all around.
My two questions are:
How to make NSPathControl link to user defaults (user selects seem to work and stick, setting a path into defaults programmatically is my problem)
How to clear values in an app interface that are bound to user defaults when the preference file is deleted. They seem to stick even after rebooting the app, etc.
The problem to bind the url property of NSPathControl to NSUserDefaults is that NSURL is not included in the supported types of property list.
Although there are methods of NSUserDefaults URLForKey: and setURL:forKey: they are convenience methods which are internally mapped to [NSURL fileURLWithPath:[defaults stringForKey:]] and setString:[url path] forKey:.
The workaround is either to use a subclass of NSValueTransformer to do the NSString - NSURL mapping or to use the standard method with a key value coding compliant instance variable which is bind to the NSPathControl element and read/write NSUserDefaults programmatically.
For the NSValueTransformer solution this is the NSValueTransformer script, the file is called PathValueTransformer.applescript
script PathValueTransformer
property parent : class "NSValueTransformer"
on transformedValueClass()
return current application's |NSURL|'s |class|()
end transformedValueClass
on allowsReverseTransformation()
return true
end allowsReverseTransformation
on transformedValue(value)
if value is not missing value then
return current application's |NSURL|'s fileURLWithPath:(value's stringByExpandingTildeInPath())
end if
return value
end transformedValue
on reverseTransformedValue(value)
if value is not missing value then
return value's |path|'s stringByAbbreviatingWithTildeInPath()
end if
return value
end reverseTransformedValue
end script
as soon as possible “ in awakeFromNib() or better initialize() “ register the value transformer with
set PathValueTransformer to current application's NSClassFromString("PathValueTransformer")
set transformer to PathValueTransformer's alloc()'s init()
current application's NSValueTransformer's setValueTransformer:transformer forName:"PathValueTransformer"
Now in Interface Builder in all Value Transformer popup menus PathValueTransformer will appear
By the way “ as Shane mentioned “ Cocoa works only with POSIX paths
tell current application's |NSURL| to set theURL to fileURLWithPath_("/Users/mark_munro/Desktop/TEST/")
Thanks… That kind of worked but I was getting crashes so I had to move on to a classic label with a path stored in text. However, I still feel like something is now different with user defaults because they are just not behaving the same as they used to.
With a text label bound to user defaults, no preference file is created and yet values are being retained. Do you know where they are going? Also, if I change my default value that I am registering it updates the value displayed. Prefiously that would only change if the preference didn’t exist.
Does that make any sense to anyone?
I am going to try just rebuilding the entire app as this is a new project and this is the first thing I tried building in it.
on applicationWillFinishLaunching_(aNotification)
set thePath to "/Users/shane/Desktop"
set theNSURL to current application's class "NSURL"'s fileURLWithPath_(thePath)
set archURL to current application's NSArchiver's archivedDataWithRootObject_(theNSURL)
set recDefaults to {aaSXPathToWatch:archURL}
set defaults to current application's NSUserDefaults's standardUserDefaults()
defaults's registerDefaults_(recDefaults)
end applicationWillFinishLaunching_
For your path control, bind values to a Model Key Path of aaSXPathToWatch, and for Value Transformer, choose NSUnarchiveFromData.
The .plist file is an implementation detail. User defaults set (and get) their values via a separate process, and how (and where) that process stores them is its business. More to the point, when it saves them to disk them is also its business. It used to be that they were stored almost immediately, but nowadays there can be a delay – for at least one OS version, it could be considerable.
If you want to clear an app’s defaults, don’t rely on deleting the file (unless you’re happy to log out as well). Use defaults in Terminal (carefully). Better still, run this script:
use framework "Foundation"
current application's NSUserDefaults's standardUserDefaults()'s setPersistentDomain:(missing value) forName:"com.yourbiz.whatever" -- id of the app in question