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

## 一：问题

> 我的新项目中尝试性的使用了`SwiftUI`进行了一部分功能的构建。 但当我需要访问相册选择图片的时候，缺犯难了。 报出了下面的错误: ![Error](/files/-MVyQOq7aAYUlc35XSjk) 因为原有的一些代理需要要求`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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/swiftui/05.imagepicker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
