DavidDens
(David Dens)
1
I am trying to implement a feature that allows a user to set their profile picture.
I am wrapping a UIImagePIckerController using a UIViewControllerRepresentable.
My Coordinator class is handling the delegate method didFinishPickingMediaWithInfo which returns the image picked.
Currently, I send this image to the reducer via an action to be stored in the state.
What is the best practice for a situation like this? Is it preferred to instead write the image to a URL and send that back instead? Since now my state is exposed to the UIImage type.
// ImagePicker.swift
import SwiftUI
import ComposableArchitecture
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
let viewStore: ViewStore<ImagePickerState, ImagePickerAction>
func makeUIViewController(
context: UIViewControllerRepresentableContext<ImagePicker>
) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(
_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>
) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
if let uiImage = info[.originalImage] as? UIImage {
parent.viewStore.send(.imagePicked(image: uiImage))
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
public struct ImagePickerState: Equatable {
var showingImagePicker: Bool
var image: UIImage?
}
public enum ImagePickerAction: Equatable {
case setSheet(isPresented: Bool)
case imagePicked(image: UIImage)
}
public struct ImagePickerEnvironment {
}
public let imagePickerReducer = Reducer<ImagePickerState, ImagePickerAction, ImagePickerEnvironment> { state, action, environment in
switch action {
case .setSheet(isPresented: true):
state.showingImagePicker = true
return .none
case .setSheet(isPresented: false):
state.showingImagePicker = false
return .none
case let .imagePicked(image):
state.image = image
return .none
eimantas
(Eimantas)
2
I store the UIKit types in State as well. I don't see any wrong doing in this. Your state is backing a view, and if you has to display a user picked image, so be it ¯\_(ツ)_/¯
JuneBash
(June Bash)
3
It may be better to store it as Data so the state is more context-independent? If you wanted to be as “pure” as possible at least, I think state should be completely unaware of how its content is being rendered by any views.
mbnz
(Malte Bünz)
4
I was asking myself that as well. I build a wrapper around uiimage which has data: Data property for the sake of conforming to Codable. It also has an id which is nice because the app stores multiple images and also has a .remove event.
But images are really big and I thought about storing the URL and maybe a thumbnail version instead since I feel it blocks the app
2 Likes