SwiftUIからUIKitの部品を使う

## 概要
SwiftUIからUIKitの部品を使うときの方法を紹介します。
サンプル用にシンプルな動作を考えました。
ボタンタップ時にラベルの文字列を変えるだけです。
動画にすると下のような感じです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/da1989ba-86d8-6619-20ec-a6e2d315b8f1.gif" width="300" />

## 環境
`Xcode 13.1`
`macOS Big Sur 11.6`


## 手順
1. `UIViewRepresentable`に準拠した構造体を作る
2. `UIKit`から画面を作成するために`makeUIView`を実装する
3. 作成した画面が更新できるように`updateUIView`を実装する
4. `UIKit`から`SwiftUI`が保持している値を変更できるようにする

## キーワードの解説
SwiftUIからUIKitを扱うにあたりキーワードがいくつかあります。
代表的なのは`makeUIView(context:)`, `updateUIView(_:context:)`, `Coordinator`です。
公式の説明を下に載せます。

#### `makeUIView(context:)`

ビューオブジェクトを作成し、その初期状態を構成します。


https://developer.apple.com/documentation/swiftui/uiviewrepresentable/makeuiview(context:)

#### `updateUIView(_:context:)`

SwiftUIからの新しい情報で、指定されたビューの状態を更新します。

https://developer.apple.com/documentation/swiftui/uiviewrepresentable/updateuiview(_:context:)

#### `Coordinator`

1. システムは、ビュー内で発生した変更をSwiftUIインターフェースの他の部分に自動的に伝達しません。
2. ビューを他のSwiftUIビューと調整する場合は、それらの相互作用を容易にするためにCoordinatorインスタンスを提供する必要があります。
3. たとえば、コーディネーターを使用して、ターゲットアクションを転送し、ビューから任意のSwiftUIビューにメッセージを委任します。

https://developer.apple.com/documentation/swiftui/uiviewrepresentable

## 実装
以下実装を進めます。
### ボタンの初期状態を実装する
`makeUIView(context:)`で`UIButton`を返してあげます。

```swift:Views/CustomButton.swift
struct CustomButton: UIViewRepresentable {
    func makeUIView(context: Context) -> UIButton {
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 160, height: 44))
        button.setTitle("Custom Button", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.addTarget(context.coordinator, action: #selector(Coordinator.didTapCustomButton(sender:)), for: .touchUpInside)
        return button
    }
}

```

### ボタンのスタイルを更新するためのメソッドを追加する
中身は空ですが`UIViewRepresentable`プロトコルに準拠するために必須のメソッドです。

```swift:Views/CustomButton.swift
struct CustomButton: UIViewRepresentable {
...
    func updateUIView(_ uiView: UIButton, context: Context) {
    }
...
}

```

### ボタンタップ時にラベルの文字列を変更できるように`Coordinator`クラスを実装する

名前解決にもつながるため、`CustomButton`クラスの中で`Coordinator`を宣言します。

```swift:Views/CustomButton.swift
struct CustomButton: UIViewRepresentable {
...
    func makeCoordinator() -> Coordinator {
        return Coordinator(button: self)
    }
    
    class Coordinator {
        var button: CustomButton
        
        init(button: CustomButton) {
            self.button = button
        }
        
        @objc func didTapCustomButton(sender: UIButton) {
            if button.text == "Default" {
                button.text = "Change"
                return
            }
            button.text = "Default"
        }
    }

...
}
```

最終的なコードは以下です。

```swift:Views/CustomView.swift
import SwiftUI

struct CustomButton: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> UIButton {
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 160, height: 44))
        button.setTitle("Custom Button", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.addTarget(context.coordinator, action: #selector(Coordinator.didTapCustomButton(sender:)), for: .touchUpInside)
        return button
    }
    
    func updateUIView(_ uiView: UIButton, context: Context) {
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(button: self)
    }
    
    class Coordinator {
        var button: CustomButton
        
        init(button: CustomButton) {
            self.button = button
        }
        
        @objc func didTapCustomButton(sender: UIButton) {
            if button.text == "Default" {
                button.text = "Change"
                return
            }
            button.text = "Default"
        }
    }
}

```

### SwiftUIから呼び出す
UIKitの部品をSwiftUIから呼び出します。
記事では以下のようにしました。

```swift:Home.swift
import SwiftUI

struct Home: View {
    @State var text: String = "Default"
    
    var body: some View {
        VStack {
            Text(text)
            CustomButton(text: $text)
        }
    }
}

struct Home_Previews: PreviewProvider {
    static var previews: some View {
        Home()
    }
}

```

以上のコードで動画のような動作になると思います。