Sunday, November 29, 2020

#1 2020-10-29 02:27:22 am

MrCee
Member
Registered: 2016-07-01
Posts: 7

ASOC NSURL to POSIX Path with NSNull (missing value)

5 days new to ASOC and purchasing Shane Stanley's book, I can tell you that I have made enormous progress. I highly recommend it.

I'd like to ask if anyone has any suggestions for improving my code? Am I referencing everything correctly? Is there a better way to handle NSNull's because any new list I create needs to keep the same count of items.

Although it does what I want, I'm not sure if I've missed any pieces of the puzzle or potentially if there is a better way? I'm running a Music.app (iTunes) script over approx. 15,000 tracks so any optimisation tips would be appreciated.


Applescript:

tell application "Music" to set theLocation to (get location of every file track in library playlist 1)
set {thePosixPath, theFolder} to my getLocationLists(theLocation)

on getLocationLists(someList)
   set theArray to current application's NSArray's arrayWithArray:someList
   set thePosixPathList to {}
   set theParentFolderList to {}
   
   repeat with i from 1 to count of theArray
       try
           --get the posix path
           set theNSURL to (theArray's objectAtIndex:(i - 1))
           set thePosixPath to theNSURL's |path|()
           set end of thePosixPathList to thePosixPath as text
           
           --get the parent folder
           set pathString to (current application's NSString's stringWithString:thePosixPath)
           set theComponentArray to pathString's pathComponents()
           set theIndex to (theComponentArray's |count|()) - 2
           set end of theParentFolderList to (theComponentArray's objectAtIndex:theIndex) as text
           
       on error
           set end of thePosixPathList to missing value
           set end of theParentFolderList to missing value
       end try
   end repeat
   
   return {thePosixPathList, theParentFolderList} as list
end getLocationLists

Thanks.

Offline

 

#2 2020-10-29 02:39:31 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11699
Website

Re: ASOC NSURL to POSIX Path with NSNull (missing value)

You could replace

Applescript:

--get the parent folder
set pathString to (current application's NSString's stringWithString:thePosixPath)
set theComponentArray to pathString's pathComponents()
set theIndex to (theComponentArray's |count|()) - 2
set end of theParentFolderList to (theComponentArray's objectAtIndex:theIndex) as text

with

Applescript:


set end of theParentFolderList to (theNSURL's URLByDeletingLastPathComponent)'s lastPathComponent() as text

getting the name of the parent folder with the NSURL API is more efficient.


regards

Stefan

Offline

 

#3 2020-10-29 09:07:44 pm

MrCee
Member
Registered: 2016-07-01
Posts: 7

Re: ASOC NSURL to POSIX Path with NSNull (missing value)

Thanks, Stefan. Your suggestion helped me understand the syntax for nested properties and improved runtime significantly.

Which leads me to ask about the parenthesis after |path|() and lastPathComponent()...

Through trial, error, and typo's I found that omitting parenthesis actually improved runtime by sometimes more than 40 seconds while still returning accurate results. Is there a reason for the runtime improvement? Could there be any adverse affects with this practice? If anyone can explain what's actually happening 'under the hood' to result in this runtime improvement that would be great.



Applescript:

tell application "Music" to set theLocation to (get location of every file track in library playlist 1)
set {thePosixPath, theFolder} to my getLocationLists(theLocation)

on getLocationLists(someList)
   set theArray to current application's NSArray's arrayWithArray:someList
   set thePosixPathList to {}
   set theParentFolderList to {}
   
   repeat with i from 1 to count of theArray
       try
           set theNSURL to (theArray's objectAtIndex:(i - 1))
           
           --set end of thePosixPathList to theNSURL's |path|() as text
           --set end of theParentFolderList to (theNSURL's URLByDeletingLastPathComponent)'s lastPathComponent() as text
           
           set end of thePosixPathList to theNSURL's |path| as text
           set end of theParentFolderList to theNSURL's URLByDeletingLastPathComponent's lastPathComponent as text
           
       on error
           set end of thePosixPathList to missing value
           set end of theParentFolderList to missing value
       end try
   end repeat
   
   return {thePosixPathList, theParentFolderList} as list
end getLocationLists

Thanks.


Filed under: PATH, NSURL

Offline

 

#4 2020-10-30 01:02:24 am

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

Re: ASOC NSURL to POSIX Path with NSNull (missing value)

MrCee wrote:

Through trial, error, and typo's I found that omitting parenthesis actually improved runtime by sometimes more than 40 seconds while still returning accurate results. Is there a reason for the runtime improvement?



When you include the parentheses, AppleScript looks up the method's signature, and converts any parameters, and the result, to what it judges are the equivalent AS/Cocoa classes or types. When you leave of the parentheses, it's the same as calling valueForKey:"methodName".

The valueForKey: method has it's own rules for conversions, so there's a fraction of time saved by not having to look up the method signature and so on.

Could there be any adverse affects with this practice?



Yes. valueForKey: will always return Cocoa object that you have to coerce to their AS equivalents, whereas AppleScript's bridging will often do it for you. For example, a method that returns a BOOL will return true or false with parentheses, but the NSNumber 0 or 1 without them.

Once you get comfortable with the difference, it can sometimes be a time saver. However, it can also be the sort of hidden trap that can make debugging difficult. I've also seen cases where it simply fails. For me personally, I rarely take the risk.

In the current case, however, there are big gains to be made using valueForKey: and its sibling valueForKeyPath: because they allow you to avoid the repeat loop altogether:

Applescript:

   set theArray to current application's NSArray's arrayWithArray:someList
   set thePosixPathList to theArray's valueForKey:"path"
   set theParentFolderList to theArray's valueForKeyPath:"URLByDeletingLastPathComponent.lastPathComponent"


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

Offline

 

#5 2020-10-30 03:58:37 am

MrCee
Member
Registered: 2016-07-01
Posts: 7

Re: ASOC NSURL to POSIX Path with NSNull (missing value)

Thanks, Shane.
Wow, results for 15,000 tracks in 3 seconds... it doesn't get better than that.

Seeing joined keys with valueForKeyPath and easily returning valueForKey without a repeat loop in the context of Music.app (iTunes) has really helped me to understand the last section of Chapter 5.

I've since simplified my code with the following and I am now ready to revisit the rest of my script with this optimised approach in mind. Cheers!

Applescript:

tell application "Music" to set theLocation to current application's NSArray's arrayWithArray:(get location of every file track in library playlist 1)
set thePosixPathList to theLocation's valueForKey:"path"
set theParentFolderList to theLocation's valueForKeyPath:"URLByDeletingLastPathComponent.lastPathComponent"

Last edited by MrCee (2020-10-30 04:28:46 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)