PHPickerをStoryBoard,SwiftUIで使う


## PHPickerとは
WWDC2020で新しいImagePickerが発表されました。
[UIImagePickerController](https://developer.apple.com/documentation/uikit/uiimagepickercontroller)に代わる新しいデフォルトのImagePickerです。
検索ができたりアクセス権限を求めないなど今までとは違った挙動ですが詳細は省きます。

https://developer.apple.com/videos/play/wwdc2020/10652/


## 動作環境
macOS 10.15.6
Xcode 12 beta 1
iOS 14 beta 1

## 使い方

```swift
// Pickerの設定
var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())

// Pickerで選択するメディアの種類をフィルタリング
config.filter = .images // videos, livePhotos

// 選択できる数を指定
config.selectionLimit = 3

// configを渡して初期化
let controller = PHPickerViewController(configuration: configuration)

// delegateをセット
controller.delegate = self

// 表示
present(controller, animated: true)
```

`config.filter`でPickerに表示されるメディアを選択できます。
現時点で `.images`, `videos`, `livePhotos`が確認できました。


`config.selectionLimit`でPickerで選択できる数値を決められます。
便利ですね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47337/c6ade80b-cfe2-aecd-f112-fe22b5f1de7f.png" width=300>


### PHPickerViewControllerDelegateの設定 

```swift
extension ViewController: PHPickerViewControllerDelegate {
    // Pickerを閉じたときにコールされる
    public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        for image in results {
            // PHPickerResultからImageを読み込む
            image.itemProvider.loadObject(ofClass: UIImage.self) { (selectedImage, error) in
                if let error = error {
                    print("error: \(error.localizedDescription)")
                    return
                }
                // UIImageに変換
                guard let wrapImage = selectedImage as? UIImage else {
                    print("wrap error")
                    return
                }

                // 選択されたimageを保管しておく
                self.selectedImages.append(wrapImage)
            }
        }
    }
}
```

## SwiftUIでの使用方法

```swift
import SwiftUI
import PhotosUI

struct ImageSelectView: View {
    // Pickerの表示/非表示フラグ
    @State private var isPresented = false
    // Imageを格納
    @State var pickerResult = UIImage(named: "defaultImage")!
    // PHPickerの設定
    var config: PHPickerConfiguration {
       var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
        config.filter = .images
        config.selectionLimit = 1
        return config
    }

    var body: some View {
        VStack(alignment: .leading) {
            Button("Image Picker") {
                // isPresentedを切り替える
                isPresented.toggle()
            }.sheet(isPresented: $isPresented) {
                // Pickerを初期化
                PhotoPicker(configuration: self.config,
                            pickerResult: $pickerResult,
                            isPresented: $isPresented)
            }
            // 選択したImageを表示する
            Image.init(uiImage: pickerResult)
                .renderingMode(.original)
                .resizable()
                .frame(width: UIScreen.main.bounds.width, height: 250, alignment: .center)
                .scaledToFill()
        }
    }
}
```


``` swift
// PHPickerViewControllerをSwiftUIで表示するためのクラス
// 参考 https://dev.classmethod.jp/articles/tried-swiftui-tutorial-secondpart/
struct PhotoPicker: UIViewControllerRepresentable {
    let configuration: PHPickerConfiguration
    @Binding var pickerResult: UIImage
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> PHPickerViewController {
            let controller = PHPickerViewController(configuration: configuration)
            controller.delegate = context.coordinator
            return controller
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {

    }

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

    /// PHPickerViewControllerDelegate => Coordinator
    class Coordinator: PHPickerViewControllerDelegate {
        private let parent: PhotoPicker

        init(_ parent: PhotoPicker) {
            self.parent = parent
        }
        // PHPickerViewControllerDelegateの設定
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            for image in results {
                image.itemProvider.loadObject(ofClass: UIImage.self) { (selectedImage, error) in
                    if let error = error {
                        print("error: \(error.localizedDescription)")
                        return
                    }
                    guard let wrapImage = selectedImage as? UIImage else {
                        print("wrap error")
                        return
                    }
                    // 選択したImageをpickerResultに格納
                    self.parent.pickerResult = wrapImage
                }
            }
            // 閉じる
            parent.isPresented = false
        }
    }
}
```

UIKitをSwiftUIで使えるようにするためひと手間必要でした

サンプルはこちら
https://github.com/lcr3/PHPickerSample