UIKitに依存するSwift PackageをVSCodeで開発する

~~Xcodeがクソすぎて~~**VSCodeが好きすぎてSwiftのコードを書くのにもVSCodeを使いたい！**
と思って調べてみたところ、どうやらSwift PackageのプロジェクトならVSCodeでもそれなりにコード補完できるようになる、ということがわかりました。

こちらにあるのがApple公式の[sourcekit-lsp](https://github.com/apple/sourcekit-lsp)(Swiftの構文補完のためのLanguage Server)リポジトリで、中を見ると[VSCode用の拡張機能](https://github.com/apple/sourcekit-lsp/tree/master/Editors/vscode)のコードもあるみたい。

なので、まずはそちらのREADMEに従ってVSCodeのsourcekit-lsp拡張機能をインストールします。上記のsourcekit-lspのリポジトリをクローンしてきて、

```
$ cd Editors/vscode
$ npm run createDevPackage
$ code --install-extension out/sourcekit-lsp-vscode-dev.vsix
```

とするだけです！

※ Xcodeのインストールが必要です。
※ `sourcekit-lsp`コマンドが実行できるようになっている必要があります。最近のXcodeなら入ってる…？もしくは上記リポジトリからビルドする。
※ npm コマンドを使うために、Node.jsのインストールが必要です。
※ code コマンドを使うために、VSCodeで`Cmd+Shift+P`から`Install code command in PATH`を実行する必要があります。

ではさっそくプロジェクトを作ります。

```
swift package init
```

プロジェクトができたら、さっそくコードを書いてみましょう。`Sources/my-swift-ios(作ったディレクトリにより異なる)`の中にMyViewController.swiftというファイルを作って次のようなコードを書きます。

```swift
import UIKit
```

…おや、`import UIKit`のところに赤い線が引かれて no such module UIKit と言われていますね。

そしたらVSCodeの設定画面を開き(`Cmd+,`)、右上の「設定（JSON)を開く」アイコンを押してsettings.jsonを開きます。
そして、その中に以下のような指定を加えます。

```jsonc
{ 
    "sourcekit-lsp.serverArguments": [
        "-Xswiftc",
        "-sdk",
        "-Xswiftc",
        "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk",
        "-Xswiftc",
        "-target",
        "-Xswiftc",
        "x86_64-apple-ios13.5-simulator",
    ]
}
```

iPhoneSimulator13.5とかios13.5-simulatorとかいう部分はXcodeのバージョンにより正しい指定が異なるので、実際に`/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs`の場所をFinderで開いて番号を確認してください。

設定ができたら、VSCodeを再起動(もしくは`Cmd+Shift+P`→Reload Window)します。

改めて先程のswiftファイルを開いてみましょう。**赤い線が消えている**と思います(消えていない場合、上記の`-Xswiftc`で渡しているパスが正しいかどうか確認してください)。

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56668/862d3ca5-6797-4e75-1cd9-5a8eb6ba6167.gif)

**コード補完できてる〜！！！！**

ちなみに、先程指定した`sourcekit-lsp.serverArguments`の設定は、`swift build`をするときにも同様に必要になります。
なので、`.vscode/tasks.json`の中にこんな感じで指定すると良いでしょう。

```json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "swift",
            "args": [
                "build",
                "-Xswiftc",
                "-sdk",
                "-Xswiftc",
                "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk",
                "-Xswiftc",
                "-target",
                "-Xswiftc",
                "x86_64-apple-ios13.5-simulator",
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
```

これでVSCodeのビルド(`Cmd+Shift+B`)をするだけでビルドできるようになります。

## テスト

ここまで書いて気付いたのですが、**テスト(`swift test`)が動かない…orz**

`.vscode/tasks.json`に以下のテスト実行の追記をしてみましたが…

```json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "swift",
            "args": [
                "build",
                "-Xswiftc",
                "-sdk",
                "-Xswiftc",
                "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk",
                "-Xswiftc",
                "-target",
                "-Xswiftc",
                "x86_64-apple-ios13.5-simulator",
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "test",
            "type": "shell",
            "command": "swift",
            "args": [
                "test",
                "-Xswiftc",
                "-sdk",
                "-Xswiftc",
                "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk",
                "-Xswiftc",
                "-target",
                "-Xswiftc",
                "x86_64-apple-ios13.5-simulator",
            ],
            "group": {
                "kind": "test",
                "isDefault": true
            }
        }
    ]
}
```

error: module 'XCTest' was created for incompatible target と言われて実行できない。

**2020/07/09追記:**
ですが、[xcodebuildコマンドを使うことでiPhone Simulator上でテストが可能である](https://qiita.com/tattn/items/894025eb6de346d07d90)ということがわかりました！


```json:.vscode/tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "swift",
            "args": [
                "build",
                "-Xswiftc",
                "-sdk",
                "-Xswiftc",
                "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk",
                "-Xswiftc",
                "-target",
                "-Xswiftc",
                "x86_64-apple-ios13.5-simulator",
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "test",
            "type": "shell",
            "command": "xcodebuild",
            "args": [
                "-scheme",
                "my-swift-ios",
                "test",
                "-destination",
                "name=iPhone 8"
            ],
            "group": {
                "kind": "test",
                "isDefault": true
            }
        }
    ]
}
```

これでiOSのコードがVSCodeでもそれなりに開発できる…かも！？！？