Thursday, August 11, 2022

#1 2022-07-26 11:31:23 am

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

defaults and dates

Not sure where I got this code. I suspect Shane posted at some point or in one of his books and I altered.... I have a library file and main script calling it. It either returns a _NSTaggedDate error or causes the script to quit unexpectedly. Ive tried a few options....

Main Script code....

Applescript:



use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use defaultsLib : script "defaultsLibBeta"
use scripting additions

property NSApp : a reference to current application's NSApp
property NSUserDefaults : a reference to current application's NSUserDefaults
property theDefaults : missing value

set theDefaults to current application's NSUserDefaults's standardUserDefaults()

set defaultsObj to defaultsLib's makeDefaultsWithID:theID factoryValues:(missing value)
set lastDate to theDefaults's objectForKey:"lastDate" ---causes NSDate Error
--tried this also
--set lastDate to defaultsObj's dateForKey:"lastDate" ---unexpectedly quits
   
set lastDate to my cocoaToASValue(lastDate)
set nowDate to current date
set todayNow to date string of (current date)
set todayStart to date (todayNow & "at 12:00:00 AM")
--
if lastDate is not missing value and lastDate < todayStart then
---do something
end

Library script ---------------------------

Applescript:

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

-- classes, constants, and enums used
property NSUserDefaults : a reference to current application's NSUserDefaults
property |NSURL| : a reference to current application's |NSURL|

script forInheritance
   -- required for inheritance
end script

on makeDefaultsWithID:scriptId factoryValues:initialValues
   script
       -- classes, constants, and enums used
       property NSUserDefaults : a reference to current application's NSUserDefaults
       property parent : forInheritance
       property scriptDefaults : missing value
       --- from logs portion
       property |NSURL| : a reference to current application's |NSURL|
       property NSFileManager : a reference to current application's NSFileManager
       property NSDirectoryEnumerationSkipsHiddenFiles : a reference to 4
       property NSString : a reference to current application's NSString
       -- Storage handlers
       
       -- This method is use for strings, records, lists, Cocoa dates
       on setObject:anObject forKey:aKey
           scriptDefaults's setObject:anObject forKey:aKey
       end setObject:forKey:
       
       on setolddate:aDate forKey:aKey
           scriptDefaults's setObject:aDate forKey:aKey
       end setolddate:forKey:
       
       on setInteger:anInteger forKey:aKey
           scriptDefaults's setInteger:anInteger forKey:aKey
       end setInteger:forKey:
       
       on setReal:aDouble forKey:aKey
           scriptDefaults's setDouble:aDouble forKey:aKey
       end setReal:forKey:
       
       on setBool:aBool forKey:aKey
           scriptDefaults's setBool:aBool forKey:aKey
       end setBool:forKey:
       
       -- File storage methods
       
       on setFile:aFile forKey:aKey
           set thePath to POSIX path of theFile
           set theURL to current application's class "NSURL"'s fileURLWithPath:thePath
           scriptDefaults's setURL:theURL forKey:aKey
       end setFile:forKey:
       
       on setAlias:anAlias forKey:aKey
           set thePath to POSIX path of anAlias
           set theURL to current application's class "NSURL"'s fileURLWithPath:thePath
           set theURL to theURL's fileReferenceURL()
           scriptDefaults's setURL:theURL forKey:aKey
       end setAlias:forKey:
       
       -- Retrievers, returning AppleScript values
       
       on stringForKey:aKey
           return (scriptDefaults's stringForKey:aKey) as string
       end stringForKey:
       
       on listForKey:aKey
           return (scriptDefaults's arrayForKey:aKey) as list
       end listForKey:
       
       on olddateForKey:aKey
           return (scriptDefaults's objectForKey:aKey) as date
       end olddateForKey:
       
       on recordForKey:aKey
           return (scriptDefaults's dictionaryForKey:aKey) as record
       end recordForKey:
       
       on integerForKey:aKey
           return (scriptDefaults's integerForKey:aKey) as integer
       end integerForKey:
       
       on realForKey:aKey
           return (scriptDefaults's doubleForKey:aKey) as real
       end realForKey:
       
       on boolForKey:aKey
           return (scriptDefaults's boolForKey:aKey) as boolean
       end boolForKey:
       
       on fileForKey:aKey
           set theURL to scriptDefaults's URLForKey:aKey
           return (theURL's |path|() as text) as «class furl»
       end fileForKey:
       
       on dateASKey:aKey
           set theDate to scriptDefaults's objectForKey:aKey
           return theDate as date
       end dateASKey:
       
       -- Handlers for dealing with AS dates
       
       on registerDateDefault:aDate forKey:aKey
           set theData to current application's NSKeyedArchiver's archivedDataWithRootObject:aDate
           set aDictionary to current application's NSDictionary's dictionaryWithObject:theData forKey:aKey
           scriptDefaults's registerDefaults:aDictionary
       end registerDateDefault:forKey:
       
       on setDate:aDate forKey:aKey
           set theData to current application's NSKeyedArchiver's archivedDataWithRootObject:aDate
           scriptDefaults's setObject:theData forKey:aKey
       end setDate:forKey:
       
       on dateForKey:aKey
           set theData to scriptDefaults's objectForKey:aKey
           return (current application's NSKeyedUnarchiver's unarchiveObjectWithData:theData) as date
       end dateForKey:
       
       
       -- Generic handlers for AppleScript values (dates, enumerators, etc)
       
       on registerASDefault:aValue forKey:aKey
           set theData to current application's NSKeyedArchiver's archivedDataWithRootObject:aValue
           set aDictionary to current application's NSDictionary's dictionaryWithObject:theData forKey:aKey
           scriptDefaults's registerDefaults:aDictionary
       end registerASDefault:forKey:
       
       on setASValue:aValue forKey:aKey
           set theData to current application's NSKeyedArchiver's archivedDataWithRootObject:aValue
           scriptDefaults's setObject:theData forKey:aKey
       end setASValue:forKey:
       
       on ASValueForKey:aKey
           set theData to scriptDefaults's objectForKey:aKey
           set aValue to (current application's NSKeyedUnarchiver's unarchiveObjectWithData:theData)
           set anArray to current application's NSArray's arrayWithArray:{aValue}
           return item 1 of (anArray as list)
       end ASValueForKey:
       
       
       
       on is_running(appName)
           tell application "System Events" to (name of processes) contains appName
       end is_running
       
       on itemExists(theItem)
           set pathStr to POSIX path of theItem
           return (NSFileManager's defaultManager()'s fileExistsAtPath:pathStr) as boolean
       end itemExists
   end script
   
   set ASPrefs to result
   set theDefaults to current application's NSUserDefaults's standardUserDefaults()
   theDefaults's registerDefaults:initialValues
   set ASPrefs's scriptDefaults to theDefaults
   return ASPrefs
end makeDefaultsWithID:factoryValues:

Last edited by mcsprodart (2022-07-26 12:53:08 pm)

Offline

 

#2 2022-07-26 05:32:01 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6791

Re: defaults and dates

You don't have an objectForKey: handler in your library.

Are you sure the defaults you're reading has an entry for the key "lastDate"?


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#3 2022-07-26 08:00:01 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6791

Re: defaults and dates

I'd also suggest that using my PrefsStorageLib is generally more reliable than the script-object approach that library uses. Available here:

https://latenightsw.com/freeware/


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#4 2022-07-28 04:53:35 pm

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

Shane,
I tried prefsStorageLib like it better BUT had similar errors. This forced me track down that I was comparing NSDate with AppleScript Dates. It seems to work in unreliably. So that's Fixed now.....

Now I have a new issues.
Testing code in Script Debugger works perfect.

Export to enhanced App and it gives this error:

The 'prepare storage' command was unable to initialize user defaults. Unknown error

Offline

 

#5 2022-07-28 05:51:48 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6791

Re: defaults and dates

You're not pass the ID of the applet are you? If so, don't -- pass (path to me).


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#6 2022-07-28 06:13:23 pm

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

I have subroutines in the applet that use the prefsLib & then scripts that need to use the same ID/Prefs.

if I put this in all of the subroutines and applet will it work?

Applescript:


if current application's id = id of me then -- must be running as applet
   prepare storage for (path to me)
else
   set theID to "com.myinfo.myapp"
   prepare storage for domain theID
end

Offline

 

#7 2022-07-28 06:32:24 pm

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

I tried and it worked until I put it into a library. I guess for now Ill put the subroutines in the Applet with the

Applescript:


prepare storage for (path to me)

and in the library I won't call it from Applet. Hopefully Bundle works fine with

Applescript:


prepare storage for domain theID

Offline

 

#8 2022-07-28 08:57:29 pm

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

I cant seem to get the error to go away in a bundle. Im using

Applescript:


prepare storage for (path to me)

but get error

Error -2700 : The 'prepare storage' command was unable to initialize user defaults. Unknown error

Offline

 

#9 2022-07-28 09:00:11 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6791

Re: defaults and dates

You use "path to me" in applets only.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#10 2022-07-29 11:56:29 am

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

Shane
It's still causing errors in a ScriptBundle being called by an Applet via Run Script. No matter what I get

The 'prepare storage' command was unable to initialize user defaults. Unknown error

If it is 

Applescript:

prepare storage for (path to me)

and

Error -2700 : The 'prepare storage' command was unable to initialize user defaults. Unknown error

if it is

Applescript:

prepare storage for domain theID

I have been troubleshooting it and the issue seems to be in the code

Applescript:


set theResult to NSUserDefaults's alloc()'s initWithSuiteName:domainString
if theResult = missing value then error "The 'prepare storage' command was unable to initialize user defaults. Unknown error"

Are you sure

Applescript:

NSUserDefaults's alloc()'s initWithSuiteName:domainString

will always return results when not an App?

Last edited by mcsprodart (2022-07-29 11:58:16 am)

Offline

 

#11 2022-07-29 01:20:20 pm

estockly
Member
Registered: 2009-01-03
Posts: 80

Re: defaults and dates

This is how I do it and it works. Are you doing anything different?

(I have a script that builds a version of this from the script in the front Script Debugger tabs, and uses whatever properties it finds in that script, and it works every time).

Applescript:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use script "PrefsStorageLib" version "1.1.1"
property prop1 : "A"
property prop2 : 2
property prop3 : {}

set myDomain to "com.myInfo.scriptInfo"
PersistentVariables(myDomain)
--StorePersistentValues()
--RetreiveStoredValues()

on PersistentVariables(myDomain)
   prepare storage for domain myDomain
   
   set my prop1 to value for key "prop1"
   set my prop2 to value for key "prop2"
   set my prop3 to value for key "prop3"
end PersistentVariables

on StorePersistentValues()
   assign value prop1 to key "prop1"
   assign value prop2 to key "prop2"
   assign value prop3 to key "prop3"
end StorePersistentValues

on RetreiveStoredValues()
   set my prop1 to value for key "prop1"
   set my prop2 to value for key "prop2"
   set my prop3 to value for key "prop3"
end RetreiveStoredValues

Offline

 

#12 2022-07-29 02:09:25 pm

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

Short answer I don't think so. It's only happening in the Script Bundle not the applet. Using the prepare storage for domain "com.somedomain.appname" doesn't work.

I am combining an Applet with script bundles inside of the applet and share the same properties. It was working before 8 very reliably. I think it has to do with Properties. SD8 clears them when saving. This is when things started breaking or there's a new include Frameworks checkbox in Export which I have tried both ways. Not blaming SD8...Im assuming its me... I think its likely a clash of variable names. For example one of my scripts had a properties theDefaults : missing value and all had theID which I was using to label the Domain. Both are in Shanes library.....but after changing still get same error.

Completely diff subject...Would love to see your script that creates the properties. Very cool.

Offline

 

#13 2022-07-29 04:22:21 pm

estockly
Member
Registered: 2009-01-03
Posts: 80

Re: defaults and dates

Here's the script. It works with ScriptDebugger and the script it produces (on the clipboard) will use Shane's PrefsStorageLib which is available here:

https://latenightsw.com/freeware/
PrefsStorageLib 1.1.0

PrefsStorageLib is a library that makes it easy for scripts to store persistent values in their existing preference property list files using the standard application defaults system. This gets around the problem where applets cannot retain values between launches because they are notarized, or locked to avoid repeated authorization dialogs. Works with macOS 10.11 or later. (Updated March 11, 2020)

Applescript:

set saveTID to AppleScript's text item delimiters

set myText to GetScriptText(1) --Change to (2) if
-- you're editing in the first window and working on the second

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 readBackupCalls 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 defaultValues to {keyName, ":", "{}"} as text
   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 {return}
set defaultValues to defaultValues as text

set storagePrepCall to {("prepare storage for (path to me)")} 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

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

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
   if return & "use script \"FileManagerLib\"" is not in myText then
       set the end of textHeader to "use script \"FileManagerLib\" version \"2.3.5\""
   end if
   set myText to (textHeader as text) & myText
   set myText to paragraphs of myText
   return myText
end GetScriptText

Last edited by estockly (2022-07-29 04:28:45 pm)

Offline

 

#14 2022-07-29 06:03:30 pm

estockly
Member
Registered: 2009-01-03
Posts: 80

Re: defaults and dates

mcsprodart wrote:

Short answer I don't think so. It's only happening in the Script Bundle not the applet. Using the prepare storage for domain "com.somedomain.appname" doesn't work.

I am combining an Applet with script bundles inside of the applet and share the same properties. It was working before 8 very reliably. I think it has to do with Properties. SD8 clears them when saving. This is when things started breaking or there's a new include Frameworks checkbox in Export which I have tried both ways. Not blaming SD8...Im assuming its me... I think its likely a clash of variable names. For example one of my scripts had a properties theDefaults : missing value and all had theID which I was using to label the Domain. Both are in Shanes library.....but after changing still get same error.

Completely diff subject...Would love to see your script that creates the properties. Very cool.



So you have two AppleScript Bundles running inside an appleScript app, right? Being called by the app?

Have you tried it this way:

Applescript:


use script "PrefsStorageLib" version "1.1.1"

prepare storage for alias applicationPath

Offline

 

#15 2022-08-01 09:49:00 am

mcsprodart
Member
Registered: 2013-03-09
Posts: 23

Re: defaults and dates

You're a genius! Sometimes the obvious solution is right in front of us. Works perfect Thanks again.

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)