Swift REPLでiOS SDKを使う

ときには Xcode や Playground で Swift コードを実行するのではなく、Swift REPL で実行したい場合がある。

しかし、Swift REPL は iOS をサポートしていないようです。swift -sdkxcrun --sdk を試してみたが、ダメです。

  1> import UIKit
expression failed to parse:
error: repl.swift:2:8: error: no such module 'UIKit'
import UIKit
       ^

いろいろ調べてみて、一つの方法として、Xcode で iOS プロジェクトを開いて、ブレークポイントで停止状態になったときに、デバッグコンソールで表示された lldb プロンプトに repl を入力すると、UIKit をインポートできる。

もう一つの方法は、lldb を使用して iOS アプリケーションのプロセスにアタッチすることで、repl で UIKit をインポートできる。

以下は手順です。

Xcode で Product -> Show Build Folder in Finder を選択する。.app ファイルは表示された Build フォルダ内の Products/Debug-iphonesimulator/ にある。そして、このアプリのパスをコピーする(Option キーを押しながら右クリックすると「パス名をコピー」が表示される)。

パスを xcrun lldb に渡す。

$ xcrun lldb -- <AppPath>

platform select ios-simulator を実行すると、iOS シミュレータの UUID が表示される。platform connect コマンドでシミュレータに接続する。

(lldb) platform select ios-simulator
(lldb) platform connect <UUID>

プロセス名を指定して、プロセスにアタッチする。 プロセス名でアタッチする場合、--waitfor オプションを付けることで、iOS アプリが実行されるのを待ってから、そのプロセスにアタッチすることができる。

(lldb) process attach --name 'AppName' --waitfor

ここでエラーが発生した。

error: attach failed: debugserver is x86_64 binary running in translation, attached failed.

原因は、Xcode は Rosetta を使っていないので、ターミナルアプリは Rosetta を使わずに開く必要がある。

次に、Xcode から iOS シミュレータを起動し、iOS アプリを実行する。

そして、lldb でプロセスを中断し、repl を実行する。 以下の Swift コードを実行すると、Xcode のデバッグコンソールにフォントファミリ一覧が表示されることを確認できる。

(lldb) continue
Process 20380 resuming
(lldb) process interrupt
Process 20380 stopped
(lldb) repl
  1> import UIKit
  2> print(UIFont.familyNames)
  3> :
(lldb) 

REPL を終了して lldb に戻すには、コロンを入力するだけです。