# 05.如何在SwiftUI中使用ImagePicker？

## 一：问题

> 我的新项目中尝试性的使用了`SwiftUI`进行了一部分功能的构建。 但当我需要访问相册选择图片的时候，缺犯难了。 报出了下面的错误: ![Error](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fe780966345dd43ff8974c9c2ba93eb911c0ebfac.png?generation=1615955080850349\&alt=media) 因为原有的一些代理需要要求`NSObjectProtocol`而我们SwifUI中的视图用的是`Struct` 而系统并没有提供在`SwiftUI`下调用相册的相关API，所以这里只能考虑自己去封装了。

## 二：SwiftUIImagePicker

```swift
struct SwiftUIImagePicker {
    @Environment(\.presentationMode) var presentationMode
    @Binding var image: UIImage?
}

extension SwiftUIImagePicker: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        let picker = UIImagePickerController()
                return picker
    }

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

    }
}
```

### 2.1 UIViewControllerRepresentable

这里使用了`UIViewControllerRepresentable`，我们的`SwiftUIImagePicker`就已经是一个标准的`SwiftUI`的`View`了。

当创建一个`SwiftUIImagePicker`，SwiftUI会自动调用`makeUIViewController()`并返回一个`UIImagePickerController`.

### 2.2 Coordinator 代理中间件

由于`SwiftUIImagePicker`作为一个SwiftUI的View依旧不能使用`NSObjectProtocol`，所以我们需要一个中间件来完成代理。

`UIViewControllerRepresentable`中贴心的提供了这样一个中间件的定义，我们只要提供实现即可\~

```swift
/// A type to coordinate with the view controller.
    associatedtype Coordinator = Void

    /// Creates the custom instance that you use to communicate changes from
    /// your view controller to other parts of your SwiftUI interface.
    ///
    /// Implement this method if changes to your view controller might affect
    /// other parts of your app. In your implementation, create a custom Swift
    /// instance that can communicate with other parts of your interface. For
    /// example, you might provide an instance that binds its variables to
    /// SwiftUI properties, causing the two to remain synchronized. If your view
    /// controller doesn't interact with other parts of your app, providing a
    /// coordinator is unnecessary.
    ///
    /// SwiftUI calls this method before calling the
    /// ``UIViewControllerRepresentable/makeUIViewController(context:)`` method.
    /// The system provides your coordinator either directly or as part of a
    /// context structure when calling the other methods of your representable
    /// instance.
    func makeCoordinator() -> Self.Coordinator
```

我们来实现一下下：

```swift
internal func makeCoordinator() -> SwiftUIImagePickerCoordinator {
    SwiftUIImagePickerCoordinator(self)
}
```

顺便实现一下选择完图片的代理方法吧：

```swift
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let uiImage = info[.originalImage] as? UIImage {
        parent.image = uiImage
    }
    parent.presentationMode.wrappedValue.dismiss()
}
```

别忘了设置一下代理：

```swift
picker.delegate = context.coordinator
```

## 三：参考

> [Importing an image into SwiftUI using UIImagePickerController](https://www.hackingwithswift.com/books/ios-swiftui/importing-an-image-into-swiftui-using-uiimagepickercontroller)
