【SwiftUI】UIViewRepresentableについて

# はじめに
SwiftUIでUIKitを使う場合は`UIViewRepresentable`を使いますが、あらためて公式ドキュメントで使い方を確認してみました。

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

# 内容
### Viewの作成と更新

##### [`func makeUIView(context: Self.Context) -> Self.UIViewType`](https://developer.apple.com/documentation/swiftui/uiviewrepresentable/makeuiview(context:))
- 必須
- Viewのオブジェクトを作成、初期状態を構成する
- Viewを初めて作成するときに、このメソッドを1回だけ呼び出す

##### [`func updateUIView(_ uiView: Self.UIViewType, context: Self.Context)`](https://developer.apple.com/documentation/swiftui/uiviewrepresentable/updateuiview(_:context:))
- 必須
- Viewの状態をSwiftUIからの新しい情報で更新する
- SwiftUIは、対応するUIKitのVIewに影響を与える変更に対してこのメ​​ソッドを呼び出す
- パラメーターで提供される新しい状態情報に一致するようにビューの構成を更新する

### サイズの指定
##### [`func sizeThatFits(_ proposal: ProposedViewSize, uiView: Self.UIViewType, context: Self.Context) -> CGSize?`](https://developer.apple.com/documentation/swiftui/uiviewrepresentable/sizethatfits(_:uiview:context:)-9ojeu)
- iOS16から使える
- 提案サイズからViewのサイズを指定する


### Viewのクリーンアップ
##### [`static func dismantleUIView(_ uiView: Self.UIViewType, coordinator: Self.Coordinator)`](https://developer.apple.com/documentation/swiftui/uiviewrepresentable/dismantleuiview(_:coordinator:)-5lee7)
-  Viewに関連する追加のクリーンアップ作業を実行する
-  たとえば、オブザーバーを削除するなど

### Coordinatorの提供
##### [`func makeCoordinator() -> Self.Coordinator`](https://developer.apple.com/documentation/swiftui/uiviewrepresentable/makecoordinator()-9e4i4)
- Viewの変更がアプリの他の部分に影響を与える可能性がある場合は、このメソッドを実装する
- UIKitのdelegateを使う場合などでも使う

### 実装例
Appleログインのボタンを`UIViewRepresentable`を使って実装した場合のイメージ👇
```swift
import SwiftUI
import AuthenticationServices

struct CustomButton: UIViewRepresentable {
    @ObservedObject var viewModel: SampleViewModel

    func makeUIView(context: Context) -> UIButton {
        var configuration = UIButton.Configuration.plain()
        var container = AttributeContainer()
        container.font = UIFont.boldSystemFont(ofSize: 16.0)
        configuration.attributedTitle = AttributedString("Apple Login", attributes: container)
        configuration.baseBackgroundColor = .white
        configuration.background.strokeWidth = 1.0

        let button = UIButton(configuration: configuration)
        button.addTarget(context.coordinator,
                         action: #selector(Coordinator.didTapButton),
                         for: .touchUpInside)
        return button
    }

    func updateUIView(_: UIButton, context _: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(customButton: self)
    }

    class Coordinator: NSObject, ASAuthorizationControllerDelegate {
        var customButton: CustomButton

        init(customButton: CustomButton) {
            self.customButton = customButton
        }

        @objc func didTapButton() {
            let provider = ASAuthorizationAppleIDProvider()
            let request = provider.createRequest()
            request.requestedScopes = [.fullName, .email]
            let controller = ASAuthorizationController(authorizationRequests: [request])
            controller.delegate = self
            controller.performRequests()
        }

        func authorizationController(controller: ASAuthorizationController,
                                     didCompleteWithAuthorization authorization: ASAuthorization) {
            // ViewModelで処理するなど   customButton.viewModel.loginWithApple()
        }

        func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {
            // ViewModelで処理するなど   customButton.viewModel.showError()
        }
    }
}
```

# おわりに
とくに整理する程の内容量ではないですが、iOS16から使える`sizeThatFits`は少し実装で使って試していきたいと思いました。

# 参考
https://developer.apple.com/documentation/swiftui/uiviewrepresentable

https://qiita.com/maiyama18/items/e36608af7e39f81af01c