How Do I Get NS Key Value for a NSURL? ($ASObjC)

finder
asobjc

(Jim Underwood) #1

###How Do I Get NS Key Value for a NSURL?

SD6 crashes on this line consistently:

  set keyDataStr to (itemNSURL's resourceValuesForKeys:nsKey |error|:(missing value))

Script Debugger 6.0.4 (6A198) on macOS 10.11.6


###Test Script to Get NS Key Values

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

set currentApp to current application

set luKeyList to {"Date Added", "Date Modified", "Date Accessed", "Date Created", "Size Allocated", "Size", "Label Color", "Label Number", "Label Local", "Type Local", "Name", "Size Allocated Total", "Size Total", "Type [kind??]"}

set nsKeyList to {currentApp's NSURLAddedToDirectoryDateKey, currentApp's NSURLAttributeModificationDateKey, currentApp's NSURLContentAccessDateKey, currentApp's NSURLCreationDateKey, currentApp's NSURLFileAllocatedSizeKey, currentApp's NSURLFileSizeKey, currentApp's NSURLLabelColorKey, currentApp's NSURLLabelNumberKey, currentApp's NSURLLocalizedLabelKey, currentApp's NSURLLocalizedTypeDescriptionKey, currentApp's NSURLNameKey, currentApp's NSURLTotalFileAllocatedSizeKey, currentApp's NSURLTotalFileSizeKey, currentApp's NSURLTypeIdentifierKey}


set itemPath to "~/Downloads/NewFolder5.zip"
--- Expand tilde (~) in Path (if it exists) --- ## @JMichaelTX
set itemPath to (current application's NSString's stringWithString:itemPath)'s stringByExpandingTildeInPath
set itemNSURL to current application's class "NSURL"'s fileURLWithPath:itemPath

set itemKeyData to "KEY DATA FOR " & itemPath

--- GET THE NS KEY VALUES FOR THIS ITEM ---

repeat with j from 1 to length of luKeyList
  
  set keyName to item j of luKeyList
  set nsKey to getItemFromIndexList(nsKeyList, luKeyList, keyName)
  
  ### NEXT STATEMENT CRASHES SD6 WITHOUT ANY WARNING OR NOTICE ###
  set keyDataStr to (itemNSURL's resourceValuesForKeys:nsKey |error|:(missing value))
  
  ## What statement do I need to get the value of the NS Key for the item?
  
  
  set itemKeyData to itemKeyDate & return & keyName & ": " & keyDataStr
  
end repeat

--~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~~

on getItemFromIndexList(pMainList, pLookupList, pLookupValue)
  
  repeat with i from 1 to length of pLookupList
    --- IF ITEM FOUND, THEN RETURN CORRESPONDING ITEM IN MAIN LIST ---
    if (item i of pLookupList is pLookupValue) then return (item i of pMainList)
  end repeat
  
  --- IF HERE, THEN ITEM WAS NOT FOUND, SO THROW ERROR ---
  error "Item NOT Found in List: " & return & "LookupValue: >>>" & pLookupValue & "<<<"
  
end getItemFromIndexList



(Jim Underwood) #2

@alldritt and @ShaneStanley, I think this may be a SD6 bug.
Even though the statement is wrong, it should not crash SD6.
Running Script Debugger 6.0.4 (6A198) on macOS 10.11.6.


I figured out how to do this.
Here’s my simple handler, based on Shane’s book:

###Get ASObjC Key Value for Finder Item

on getNSKeyValue(pPosixPath, pnsKeyName)
  ## Based on Script #C14-1 of Everyday AppleScriptObjC by Shane Stanley
  
  local theURL, theResult, theValue, valueStr
  
  set theURL to current application's class "NSURL"'s fileURLWithPath:pPosixPath
  set {theResult, theValue, theError} to theURL's getResourceValue:(reference) forKey:pnsKeyName |error|:(reference)
  if theResult as boolean is false then
    error (theError's localizedDescription() as text)
  else
    set theValue to theValue as list
    set valueStr to (item 1 of theValue) as text
    if (valueStr = "missing value") or (valueStr = "") then set valueStr to "NOT FOUND"
    return valueStr
  end if
end getNSKeyValue

###Test Script to Demo Getting ASObjC Key Values

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

set currentApp to current application

--- THESE TWO LISTS MUST BE IN SYNCHRONIZED ORDER ---
--    (luKeyList is used as a lookup list for nsKeyList)

set luKeyList to {"Date Added", "Date Modified", "Date Accessed", "Date Created", ¬
  "Size Allocated", "Size", "Label Color", "Label Number", "Label Local", ¬
  "Type Local", "Name", "Size Allocated Total", "Size Total", "Type"}

set nsKeyList to {currentApp's NSURLAddedToDirectoryDateKey, ¬
  currentApp's NSURLAttributeModificationDateKey, currentApp's NSURLContentAccessDateKey, ¬
  currentApp's NSURLCreationDateKey, currentApp's NSURLFileAllocatedSizeKey, ¬
  currentApp's NSURLFileSizeKey, currentApp's NSURLLabelColorKey, currentApp's NSURLLabelNumberKey, ¬
  currentApp's NSURLLocalizedLabelKey, currentApp's NSURLLocalizedTypeDescriptionKey, ¬
  currentApp's NSURLNameKey, currentApp's NSURLTotalFileAllocatedSizeKey, ¬
  currentApp's NSURLTotalFileSizeKey, currentApp's NSURLTypeIdentifierKey}


set itemPath to "~/Downloads/NewFolder5.zip"
set itemKeyData to itemPath & return & "(Copied to clipboard)" & return

--- Expand tilde (~) in Path (if it exists) --- ## @JMichaelTX
set itemPath to (current application's NSString's stringWithString:itemPath)'s stringByExpandingTildeInPath
set itemNSURL to current application's class "NSURL"'s fileURLWithPath:itemPath

--- GET THE NS KEY VALUES FOR THIS ITEM ---

repeat with j from 1 to length of luKeyList
  
  set keyName to item j of luKeyList
  set nsKey to getItemFromIndexList(nsKeyList, luKeyList, keyName)
  
  set keyDataStr to my getNSKeyValue(itemPath, nsKey)
  
  ## What statement do I need to get the value of the NS Key for the item?
  
  
  set itemKeyData to itemKeyData & return & keyName & ":" & tab & keyDataStr
  
end repeat

set theClipboard to itemKeyData as text
display dialog itemKeyData with title "ASObjC Key Values for Finder Item"

--~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~~

on getNSKeyValue(pPosixPath, pnsKeyName)
  ## Based on Script #C14-1 of Everyday AppleScriptObjC by Shane Stanley
  
  local theURL, theResult, theValue, valueStr
  
  set theURL to current application's class "NSURL"'s fileURLWithPath:pPosixPath
  set {theResult, theValue, theError} to theURL's getResourceValue:(reference) forKey:pnsKeyName |error|:(reference)
  if theResult as boolean is false then
    error (theError's localizedDescription() as text)
  else
    set theValue to theValue as list
    set valueStr to (item 1 of theValue) as text
    if (valueStr = "missing value") or (valueStr = "") then set valueStr to "NOT FOUND"
    return valueStr
  end if
end getNSKeyValue

on getItemFromIndexList(pMainList, pLookupList, pLookupValue)
  
  local iLU
  
  repeat with iLU from 1 to length of pLookupList
    --- IF ITEM FOUND, THEN RETURN CORRESPONDING ITEM IN MAIN LIST ---
    if (item iLU of pLookupList is pLookupValue) then return (item iLU of pMainList)
  end repeat
  
  --- IF HERE, THEN ITEM WAS NOT FOUND, SO THROW ERROR ---
  error "Item NOT Found in List: " & return & "LookupValue: >>>" & pLookupValue & "<<<"
  
end getItemFromIndexList



(Shane Stanley) #3

That’s not an SD bug – it’s the reality of AppleScriptObjC. As the AppleScript Release Notes for 10.10 put it:

Warning: Using Objective-C frameworks from AppleScript provides many new and exciting opportunities to crash the host process.

It’s crashing because resourceValuesForKeys: is expecting a list or array of keys, whereas you are passing a single key.

AppleScriptObjC is calling Objective-C, which is just an extended version of C. The objects you are passing around are pointers, which are basically addresses. So when you pass an address where the address of a list or array is expected, and it contains something else, there’s every chance you will crash the host application. This sort of crash happens at such a low level it can’t be trapped.