AppleScript スクリプトバンドルの高速化

#スクリプトバンドルでのループ処理
今回は、以前投稿した
[AppleScript ハンドラの高速化](https://qiita.com/ginn_nezz/items/e4f2a5264a31b762be9e)を
[スクリプトバンドル](https://qiita.com/ginn_nezz/items/65f2201ff3babcb2e641)で
実践してみましょう。

以前と同じ条件で、
**(1)1〜10,000をループさせて、
(2)ループ変数とリスト変数をハンドラへ渡し、
(3)ハンドラでループ変数を文字列化してリストに追加、
(4)ハンドラからリストを戻す。**
の時間を計測します。

まずは
**AppleScript** 標準リストバージョン。

ライブラリとして以下を
「myLoop.scpt」で保存、
Script Librariesに入れます。

<details><summary>**サンプルコード1**</summary><div>

```AppleScript:sample1
on do(i, theResult)
	set end of theResult to i as string
	return theResult
end do
```
</div></details>

メインのスクリプトバンドルは
以下で保存してください。
ファイル名は何でもいいです。

<details><summary>**サンプルコード2**</summary><div>

```AppleScript:sample2
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

set theResult to {}

repeat with i from 1 to 10000
	set theResult to script "myLoop"'s do(i, theResult)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

theResult
```
</div></details>

結果は、
![sanple27_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500852/2685e1e0-45e8-73e1-39c7-6d1ea3361071.png)
…ま、
遅いだろうとは思ってましたが、
4秒に手が届きそうな遅さと知って、
殺意が湧いてきました。

要するに、
**Script Libraries** のハンドラで
10,000回の受け渡しをやると
基本的に遅いのです。

#script object のループ処理

では、
同じことを **script object** を介して
実行してみます。

同様に、
ライブラリとして以下を
「myLoop.scpt」で保存、
Script Librariesに入れます。

<details><summary>**サンプルコード3**</summary><div>

```AppleScript:sample3
script theIterator
	property record : 0
end script

script theResult
	property record : {}
end script

on do(theIterator, theResult)
	set end of record of theResult to record of theIterator as string
	return theResult
end do
```
</div></details>

※後ほど改めて解説しますが、
　トップレベル(メインスレッド)にも受け手のハンドラ側にも
　**script object** の宣言が必要になります。

続いて、
メインのスクリプトバンドルは
以下で保存してください。
こちらもファイル名は何でもいいです。

<details><summary>**サンプルコード4**</summary><div>

```AppleScript:sample4
use framework "Foundation"
use scripting additions

set eDate to current application's NSDate's timeIntervalSinceReferenceDate()

script theIterator
	property record : 0
end script

script theResult
	property record : {}
end script

set record of theResult to {}

repeat with i from 1 to 10000
	set record of theIterator to i
	set theResult to script "myLoop"'s do(theIterator, theResult)
end repeat

display alert ((((current application's NSDate's timeIntervalSinceReferenceDate()) - eDate) & "秒かかりました") as string)

record of theResult
```
</div></details>

結果は、
![sanple27_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500852/3e39d92d-3352-2f19-f369-7fd0d31c0ae4.png)
そのスピード、**1/25！**
とにかく気持ちいい。

ここまでくると、
**AppleScript** プログラムで使う変数は全て、
**script object** にしてしまうのがいいです。
#script object 高速化の注意点
以前にも書いたことですが、
受け渡しは
**script object** を渡すこと。

ハンドラ部分を再度掲載しますが、
処理自体は
**record of (スクリプト名)**で行ない、
引数、戻り値は (スクリプト名)にしてください。
そうしないと高速化につながりません。

```AppleScript:sample5
on do(theIterator, theResult)
	set end of record of theResult to record of theIterator as string
	return theResult
end do
```

さらにもう一点、
メインスレッド(トップレベル)側と
ライブラリ側とで、
**script object** の指定をそれぞれ行なうこと。

```AppleScript:sample6
script theIterator
	property record : 0
end script

script theResult
	property record : {}
end script
```

この二点をおさえておけば、
必ず高速化します。
慣れるまで戸惑いもあるかもしれませんが、
試してみて損はありません。