Online Book Reader

Home Category

AppleScript_ The Definitive Guide - Matt Neuburg [204]

By Root 1620 0
complex. Suppose we want to ask BBEdit to make uppercase every word starting with "t":

tell application "BBEdit"

repeat with w in every word of document 1

if contents of text of w begins with "t" then

change case w making raise case

end if

end repeat

end tell

That looks very neat, but looks are deceptive. Each time through the loop, w is set to this:

a reference to item 1 of every word of document 1 of application "BBEdit"

a reference to item 2 of every word of document 1 of application "BBEdit"

a reference to item 3 of every word of document 1 of application "BBEdit"

And so on. Our code is sending BBEdit an Apple event for every word in the document, and this Apple event asks BBdit to evaluate the concept every word afresh each time, even though the meaning of that concept is not changing significantly as we loop. If there are a thousand words and just two beginning with "t", that's a massive waste.

We can eliminate the repeated evaluation of every word by gathering the words of the document once, before the loop:

tell application "BBEdit"

set L to (get every word of document 1)

repeat with w in L

if contents of text of w begins with "t" then

change case w making raise case

end if

end repeat

end tell

But we are still sending one Apple event for every word in the document. With a single much more efficient Apple event at the outset, we can ask BBEdit to give us a list of just those words we will need to change:

tell application "BBEdit"

set L to ¬

(get every word of document 1 where contents of text of it begins with "t")

repeat with w in L

change case w making raise case

end repeat

end tell

That way, even if our document consists of a thousand words, if there are just two words beginning with "t", our code will send just three Apple events: one to gather the list of references to the two words, and then two more to change their case.

Be alert for implicit Apple events you may be sending without intending to do so. Reread Chapter 12 to see how capturing a reference implies the possibility that using that reference might send an Apple event. In a loop, that sort of thing can add up.

Finally, consider that you might not have to loop at all. The target application may be smart enough do what you want with a single command. There's no need for the loop in this code to gather the names of Finder folders:

tell application "Finder"

set L to (get every folder)

set L2 to {}

repeat with f in L

set end of L2 to name of f

end repeat

end tell

Instead, you can say this (see "Operations on Multiple References" in Chapter 11):

tell application "Finder"

set L to (get name of every folder)

end tell

List Access


When you access an attribute of a list, it is much faster to target a reference to the list, or the list as a script property, than to target the list directly. It's not entirely clear why this is; it seems like a bug. But it's a venerable and acknowledged bug, because even Apple's earliest documentation on AppleScript contains an example illustrating this point.

In this code (based on Apple's example) we total the numbers in a long list:

set L to {}

set total to 0

set bignum to 5000

repeat with i from 1 to bignum

set end of L to i

end repeat

repeat with i from 1 to bignum

set total to total + (item i of L)

end repeat

total -- 12502500, and it takes about 22 seconds to run on my machine

The big slowdown here is the second repeat block, accessing items of the list. If we access these items by way of a reference to the list, things speed up dramatically:

set L to {}

set refL to a reference to L

set total to 0

set bignum to 5000

repeat with i from 1 to bignum

set end of L to i

end repeat

repeat with i from 1 to bignum

set total to total + (item i of refL)

end repeat

total -- 12502500, and it took less than a second

Instead of a reference, you can get the same extraordinary speed bump by referring to the list as a script property:

set L to {}

set total to 0

set bignum to 5000

repeat with i from 1 to bignum

set end of L to i

end repeat

repeat

Return Main Page Previous Page Next Page

®Online Book Reader