------------------------- | Photo Picker | |-----------------------| | [Take Photo] [Gallery]| | | | | | [ImageView] | | | | | -------------------------
Camera and photo library in iOS Swift - Mini App: Build & Ship
import SwiftUI import PhotosUI import UIKit struct PhotoPickerScreen: View { @State private var image: Image? = nil @State private var showCamera = false @State private var showPhotoLibrary = false var body: some View { VStack { HStack { Button("Take Photo") { // TODO: Show camera } .disabled(!UIImagePickerController.isSourceTypeAvailable(.camera)) Button("Gallery") { // TODO: Show photo library } } .padding() Spacer() if let image = image { image .resizable() .scaledToFit() .frame(maxWidth: 300, maxHeight: 300) } else { Text("No photo selected") .foregroundColor(.gray) } Spacer() } .sheet(isPresented: $showCamera) { // TODO: Camera picker } .sheet(isPresented: $showPhotoLibrary) { // TODO: Photo library picker } } } struct PhotoPickerScreen_Previews: PreviewProvider { static var previews: some View { PhotoPickerScreen() } }
import SwiftUI import UIKit struct PhotoPickerScreen: View { @State private var image: Image? = nil @State private var showCamera = false @State private var showPhotoLibrary = false @State private var inputImage: UIImage? = nil var body: some View { VStack { HStack { Button("Take Photo") { showCamera = true } .disabled(!UIImagePickerController.isSourceTypeAvailable(.camera)) .padding() Button("Gallery") { showPhotoLibrary = true } .padding() } Spacer() if let image = image { image .resizable() .scaledToFit() .frame(maxWidth: 300, maxHeight: 300) } else { Text("No photo selected") .foregroundColor(.gray) } Spacer() } .sheet(isPresented: $showCamera) { ImagePicker(sourceType: .camera, selectedImage: $inputImage) } .sheet(isPresented: $showPhotoLibrary) { ImagePicker(sourceType: .photoLibrary, selectedImage: $inputImage) } .onChange(of: inputImage) { _ in loadImage() } } func loadImage() { guard let inputImage = inputImage else { return } image = Image(uiImage: inputImage) } } struct ImagePicker: UIViewControllerRepresentable { 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.selectedImage = uiImage } picker.dismiss(animated: true) } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true) } } var sourceType: UIImagePickerController.SourceType @Binding var selectedImage: UIImage? func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.delegate = context.coordinator picker.sourceType = sourceType return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} } struct PhotoPickerScreen_Previews: PreviewProvider { static var previews: some View { PhotoPickerScreen() } }
This solution uses SwiftUI with a UIViewControllerRepresentable wrapper called ImagePicker to access the camera and photo library.
Two buttons let the user choose between taking a photo or picking from the gallery. The 'Take Photo' button is disabled if the device has no camera.
When a photo is selected or taken, it updates the inputImage state, which triggers loadImage() to convert it to a SwiftUI Image and display it.
The ImagePicker uses UIKit's UIImagePickerController to handle the camera and photo library, with a coordinator to manage delegate callbacks.
This approach handles permissions automatically by the system when accessing camera or photo library.
------------------------- | Photo Picker | |-----------------------| | [Take Photo] [Gallery]| | | | | | [Selected Image] | | | | | -------------------------
Practice
sourceType to .camera in UIImagePickerController?Solution
Step 1: Understand
ThesourceTypeusagesourceTypeproperty ofUIImagePickerControllerdefines where the image will come from.Step 2: Identify the effect of
Setting.camerasourceTypeto.cameraopens the device camera to take a new photo.Final Answer:
To allow the user to take a new photo using the device camera -> Option CQuick Check:
sourceType = .camerameans take new photo [OK]
- Confusing .camera with .photoLibrary
- Thinking .camera records video by default
- Assuming .camera opens settings
UIImagePickerController and set its delegate in Swift?Solution
Step 1: Correct initialization syntax
In Swift,UIImagePickerController()requires parentheses to create an instance.Step 2: Assign delegate properly
The delegate is assigned asselfwithout parentheses because it is a property, not a function call.Final Answer:
let picker = UIImagePickerController() picker.delegate = self -> Option BQuick Check:
Initialize with () and assign delegate without () [OK]
- Forgetting parentheses when creating UIImagePickerController
- Using parentheses when assigning delegate
- Declaring picker without parentheses
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage {
print("Image selected")
} else {
print("No image found")
}
}Solution
Step 1: Check the delegate method behavior
The methodimagePickerController(_:didFinishPickingMediaWithInfo:)is called after user picks a photo.Step 2: Understand the info dictionary
Theinfodictionary contains the key.originalImagewith the selected UIImage if successful.Final Answer:
Image selected -> Option DQuick Check:
Image exists in info dictionary after selection [OK]
- Assuming image is nil after selection
- Confusing delegate method names
- Not casting info dictionary value properly
let picker = UIImagePickerController() picker.sourceType = .camera picker.delegate = self present(picker, animated: true)
Solution
Step 1: Check delegate conformance requirements
To useUIImagePickerControllerdelegate methods, the class must conform toUIImagePickerControllerDelegateandUINavigationControllerDelegate.Step 2: Identify missing conformance
If the class does not conform, delegate methods won't be called and picker won't work properly.Final Answer:
Missing UIImagePickerControllerDelegate and UINavigationControllerDelegate conformance -> Option AQuick Check:
Delegate protocols must be adopted for picker to work [OK]
- Forgetting to add delegate protocols to class
- Assigning delegate after presenting picker
- Using wrong sourceType value
Solution
Step 1: Understand
A singlesourceTypeflexibilityUIImagePickerControllercan have itssourceTypeset to either.cameraor.photoLibrarybefore presenting.Step 2: Handle user choice before presenting picker
Based on user selection, set thesourceTypedynamically and present the picker once.Final Answer:
Set sourceType dynamically based on user choice, then present a single UIImagePickerController -> Option AQuick Check:
One picker, sourceType changes per user choice [OK]
- Trying to present two pickers at once
- Using savedPhotosAlbum to cover camera
- Mixing custom UI unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
