ImageForge 1.3.1:ウインドウ1つ、リスト1つ
両プラットフォームで同じ症状——アプリに複数の画像を渡すと空のまま開く——でしたが、原因はまったく別の2つでした。それぞれ何だったのかをお話しします。
両プラットフォームで同じ症状——アプリに複数の画像を渡すと空のまま開く——でしたが、原因はまったく別の2つでした。それぞれ何だったのかをお話しします。
ユーザーからの1件の報告、2つのOS、そして共通点のない2つの根本原因。Macでは、Dockアイコンに画像を4枚ドロップするとウインドウが4つ開き、バッチはそのうちの1つに入りました。Windowsでは、「ImageForgeで開く」を選んでも、何枚渡してもアプリは空のリストで開きました。1.3.1はその両方を直します。そして、それぞれがどう壊れていたのかは語る価値があります。
Dockアイコンに画像を4枚ドロップすると、それぞれ空のリストを持つウインドウが4つ開き、どれがバッチを受け取るかを奪い合っていました。原因は私たちのコードではありません。メインウインドウがSwiftUIのWindowGroupだったからです。WindowGroupは、macOSが書類を開くApple Eventを届けたときに書類1つにつきウインドウを1つ開きます。システムのトレースは明快でした——4ファイルを含む単一のイベント、その直後に作られた4つのウインドウ。すべて、私たちのコードがパスを1つも見る前の出来事です。バッチはそのうちの1つに入り、どれが前面に来るかは制御できませんでした。だから、何も入っていない状態でアプリが開いたように見え、やり直しても空のウインドウが増えるだけだったのです。
解決策は、問題を防御的なコードで囲むことではなく、このアプリが元々そうであったもの——ウインドウ1つ、リスト1つ——を宣言することでした。シーンはSwiftUIのWindowになり、Apple Eventにもそれ以外にも複製できない単一インスタンスです。同じ理由で「ファイル」メニューの「新規ウインドウ」もなくなりました。ウインドウを閉じた場合は、「ウインドウ」▸「ImageForgeウインドウ」(⌘0)、Dockアイコンのクリック、またはメニューバーの項目から開き直せます。
Windows版は最初のリリースからファイルの種類の関連付けを宣言していました。だからWindowsは「ImageForgeで開く」を提示し、アイコンへのドロップも受け付けていました。ただ、一度も読んでいなかったのです。WinUIはすべてのアクティベーションを1つの起動メソッドに集約しますが、私たちのそれはウインドウを作って引数を捨てていました。関連付けは飾りで、1枚渡しても20枚渡してもアプリは空のリストで開いていました。
直す過程で、私たちの思い込みが1つ崩れました。パッケージ化されたデスクトップアプリの場合、Windowsのシェルは選択をひとつのアクティベーションとして渡しません。ファイルごとにプロセスを1つ起動し、それぞれのコマンドラインにパスが1つだけ載ります。画像4枚は4プロセスだったのです。そこで修正は2つの半分から成ります。コマンドラインからパスを読むこと、そして主プロセスを1つ選び、他のプロセスが終了する前に自分のファイルを渡すこと。結果は最初からそうあるべきだった姿です——何枚選んでも、ウインドウ1つ、リスト1つ。
どちらのバグも、アプリとOSの境界にありました。ユニットテストでは覆えない部分です。システムが実際に何をするかは、実際にやらせて見るしか知りようがないからです。どちらもコードを考えて見つけたのではなく、システムのトレースを読んで見つけました。そしてどちらの場合も、コードは私たちが指示したとおりに動いていたのです。1.3.1はMac App StoreとMicrosoft Storeで公開されています。いつものとおり、処理はすべてお使いの端末で行われ、アップロードは一切ありません。
Mac App StoreとMicrosoft Storeで無料。どちらも同じオンデバイスエンジンです。1.3.1は公開中。