Resource Key for NSURLs

I’m working on the following script just as a matter of general interest. The script works as I want except that I want it to return URLs instead of paths. I thought this might be accomplished by changing NSURLPathKey to a resource key that returns a URL, but I couldn’t find anything that works.

As an alternative, I rewrote the section of the script that creates an array of dictionaries to separately add the resource key values and then the URL to the dictionary. This worked OK but was slow.

Can the following be made to work by changing NSURLPathKey to a resource key for NSURLs? Thanks for the help.

use framework "Foundation"
use scripting additions

--Set source folder to current user's Home folder
set theFolder to current application's NSHomeDirectory()
set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder

--Get contents of source folder
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden items and package contents

--Set variables to resource keys
set folderKey to current application's NSURLIsDirectoryKey
set regularFileKey to current application's NSURLIsRegularFileKey
set fileKey to current application's NSURLPathKey --returns path and works OK but I want URLs

--Create array of dictionaries with resource key values
set fileData to current application's NSMutableArray's new()
repeat with anItem in folderContents
	(fileData's addObject:(anItem's resourceValuesForKeys:{folderKey, regularFileKey, fileKey} |error|:(missing value)))
end repeat

--Filter based on desired resource key
set thePredicate to current application's NSPredicate's predicateWithFormat_("%K == YES", folderKey)
# set thePredicate to current application's NSPredicate's predicateWithFormat_("%K == YES", regularFileKey)
(fileData's filterUsingPredicate:thePredicate)
return (fileData's valueForKey:fileKey) as list

You can get a bunch of fileURL back from FileManager with the following line:

set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()'s valueForKey:"absoluteString"

That resuts an array of file:///Users/Robert/etc. Is that what you seek?

VikingOSX. Thanks for the suggestion.

I want the script to return an array of NSURLs, and, when coerced to a list, a list of file objects. I don’t understand how your suggestion would accomplish that.

BTW, there was an error in my script, and I’ve fixed that.

NSURL doesn’t have a resource for itself, but couldn’t you just add the URL to the fileData items and get the key for it? For example:

repeat with anItem in folderContents
   set itemInfo to current application's NSMutableDictionary's new()
   (itemInfo's setObject:anItem forKey:"URLKey") -- or whatever key name
   (itemInfo's addEntriesFromDictionary:(anItem's resourceValuesForKeys:{folderKey, regularFileKey, fileKey} |error|:(missing value)))
   (fileData's addObject:itemInfo)
end repeat

And then return (fileData's valueForKey:"URLKey"). Note that coercing to a list would result in AppleScript file items.

red_menace. Thanks for the response.

I had tried that approach but it was slow (at least compared with the approach that returned paths). I assume that the additional time is due to the time it takes to create the array of dictionaries. However, until I get the other version working, I can’t be sure of this.

It would seem a bit odd if NSURL had a resource for itself. :smile: Though, in the back of my mind, I seem to recall seeing that done.

use framework "Foundation"
use scripting additions

--Set source folder to current user's Home folder
set theFolder to current application's NSHomeDirectory()
set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder

--Get contents of source folder
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden items and package contents

--Set variables for resource keys
set folderKey to current application's NSURLIsDirectoryKey
set regularFileKey to current application's NSURLIsRegularFileKey

--Create array of dictionaries with resource key and URL values
set fileData to current application's NSMutableArray's new()
repeat with anItem in folderContents
	set dictionaryOne to (anItem's resourceValuesForKeys:{folderKey, regularFileKey} |error|:(missing value))'s mutableCopy()
	set dictionaryTwo to (current application's NSDictionary's dictionaryWithObject:anItem forKey:"URLKey")
	(dictionaryOne's addEntriesFromDictionary:dictionaryTwo)
	(fileData's addObject:dictionaryOne)
end repeat

--Filter based on desired resource key
set thePredicate to current application's NSPredicate's predicateWithFormat_("%K == YES", folderKey)
# set thePredicate to current application's NSPredicate's predicateWithFormat_("%K == YES", regularFileKey)
(fileData's filterUsingPredicate:thePredicate)
return (fileData's valueForKey:"URLKey") as list

BTW, I had some trouble getting the syntax to work correctly, so I took a minutely different approach than you suggest.

As you are using a loop anyway wouldn’t it be more efficient to do the filtering instantly in the loop?
Then you can add the current NSURL to the fileData array

And you can speed up the script a bit by including the keys in the includingPropertiesForKeys: parameter.

Something like this

use framework "Foundation"
use scripting additions

--Set source folder to current user's Home folder
set theFolder to current application's NSHomeDirectory()
set theFolder to current application's |NSURL|'s fileURLWithPath: theFolder

--Set variables for resource keys
set folderKey to current application's NSURLIsDirectoryKey
set regularFileKey to current application's NSURLIsRegularFileKey
set fileKey to current application's NSURLPathKey

--Get contents of source folder
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{folderKey, regularFileKey, fileKey} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden items and package contents

--Create array of dictionaries with resource key and URL values
set fileData to current application's NSMutableArray's new()
repeat with anItem in folderContents
	set theResource to (anItem's resourceValuesForKeys:{folderKey, regularFileKey, fileKey} |error|:(missing value))
	set theValue to (theResource's objectForKey:folderKey)
	if theValue as boolean then
		(fileData's addObject:anItem)
	end if
end repeat

return fileData as list

By the way: NSURL has a property hasDirectoryPath to check if the URL represents a directory

Stefan. Thanks for the response.

I had previously run timing tests with Script Geek. and the approach you suggest took 47 milliseconds and the approach I use above took 60 milliseconds. So, I agree with what you say, but I like to try out different ways of doing stuff.

I had also previously run tests and including the keys in the includingPropertiesForKeys: parameter made absolutely no difference in the time it took for the script to run. I know this is counter intuitive but I spent a fair amount of time testing this with Script Geek.

Interesting. The documentation of NSFileMaker says

The values for these keys are cached in the corresponding NSURL objects.

so you can assume that retrieving the values takes less time.

Have you run the script on your home folder which likely takes more time than 60 ms? :wink:

I have a really-small Home folder.

It’s been a year or more since I ran the timing tests for including and not including the resource keys in the includingProperitesForKeys: parameter. Later today, I will rerun these tests and post the results.

I’m doing this…

on FileSystem_Convert_Objects_To_Files(fileSystemObjectList)
	try
		set fileSystemObjectList to (fileSystemObjectList) as list
		repeat with currentIndex from 1 to length of fileSystemObjectList
			set item currentIndex of fileSystemObjectList to (item currentIndex of fileSystemObjectList) as «class furl»
		end repeat
		return fileSystemObjectList
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Convert_Objects_To_Files>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Convert_Objects_To_Files

So, used in your original post…

    --Running under AppleScript 2.8, MacOS 15.7.5
    use framework "Foundation"
    use scripting additions
    
    --Set source folder to current user's Home folder
    set theFolder to ((current application's NSHomeDirectory()) as text) & "/Desktop"
    set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
    
    --Get contents of source folder
    set fileManager to current application's NSFileManager's defaultManager()
    set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden items and package contents
    
    FileSystem_Convert_Objects_To_Files(folderContents)

    -->>"{file "Macintosh HD:Users:UserNameGoesHere:Desktop:IMG_3861.psd", file "Macintosh HD:Users:UserNameGoesHere:Desktop:IMG_3861.psb", file "Macintosh HD:Users:UserNameGoesHere:Desktop:Screenshot 2026-05-18 at 9.37.46 AM.png", file "Macintosh HD:Users:UserNameGoesHere:Desktop:sort:", file "Macintosh HD:Users:UserNameGoesHere:Desktop:sort:untitled folder:", file "Macintosh HD:Users:UserNameGoesHere:Desktop:sort:untitled folder:Screenshot 2026-05-14 at 5.58.21 PM.png", etc


    
    on FileSystem_Convert_Objects_To_Files(fileSystemObjectList)
        try
            set fileSystemObjectList to (fileSystemObjectList) as list
            repeat with currentIndex from 1 to length of fileSystemObjectList
                set item currentIndex of fileSystemObjectList to (item currentIndex of fileSystemObjectList) as «class furl»
            end repeat
            return fileSystemObjectList
        on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
            error "<FileSystem_Convert_Objects_To_Files>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
        end try
    end FileSystem_Convert_Objects_To_Files