You are currently viewing How to Use the SwiftUI PhotosPicker

How to Use the SwiftUI PhotosPicker

In this year’s WWDC, Apple brings in tons of improvements to SwiftUI, one particular that catches my attention is the PhotosPicker view (some might call it Image Picker). Yes, you are right! SwiftUI is finally getting its own native photo picker view in iOS 16.

The PhotosPicker view supports all the common functionalities that PHPickerViewController has. Functionalities such as single and multiple selections, asset type filtering, and album switching are all included.

The way of using the PhotosPicker view is actually pretty straightforward. Let me show you how.


Using the PhotosPicker view

First things first, let’s first import the SwiftUI and PhotosUI module. After that, define a state named selectedItem of type PhotosPickerItem.

import SwiftUI
import PhotosUI

struct ContentView: View {
    
    @State private var selectedItem: PhotosPickerItem? = nil
    
    // ...
    // ...
    // ...
}

For better memory efficiency, the asset selected by the user will be given to us in the form of PhotosPickerItem. We will use it to retrieve the underlying asset later on.

With that in mind, we can add the PhotosPicker view to the content view’s body like so:

var body: some View {

    PhotosPicker(
        selection: $selectedItem,
        matching: .images,
        photoLibrary: .shared()) {
            Text("Select a photo")
        }
}

For simplicity’s sake, I have configured the PhotosPicker view to show a single selection photos picker that only displays images. Feel free to check out the official documentation for more configuration options.

Based on my personal experience, I notice that it is mandatory to set photoLibrary to .shared() when initializing the PhotosPicker view. If we omit it, the binding of $selectedItem will not work. I am not sure why is it so, maybe it is a bug in the beta release that will be fixed in the near future. If anyone knows the reason behind it, do hit me up on Twitter.

Now, if you go ahead and run the sample code, you will see the PhotosPicker view labeled as “Select a photo” at the center of the screen. Tapping on it will bring up the iOS native photos picker.

Using the SwiftUI PhotosPicker view introduced in iOS 16
Using the SwiftUI PhotosPicker view

Handling Asset Selection

We are going to retrieve the user-selected asset in the form of Data. Thus let’s go ahead and define the state for that:

@State private var selectedImageData: Data? = nil

The way to handle asset selection is pretty straightforward. The concept is to use the PhotosPicker view’s onChange() modifier to detect the change of selectedItem. After that, we will use the selectedItem‘s loadTransferable() method to get the underlying asset.

.onChange(of: selectedItem) { newItem in
    Task {
        // Retrive selected asset in the form of Data
        if let data = try? await newItem?.loadTransferable(type: Data.self) {
            selectedImageData = data
        }
    }
}

Lastly, let’s show the selected image right below the PhotosPicker view.

if let selectedImageData,
   let uiImage = UIImage(data: selectedImageData) {
    Image(uiImage: uiImage)
        .resizable()
        .scaledToFit()
        .frame(width: 250, height: 250)
}

That’s it for handling asset selection. Run the sample code again to see everything in action.

Selecting image in the iOS photos picker
Selecting image in the iOS photos picker

Here’s the full sample code:

import SwiftUI
import PhotosUI

struct ContentView: View {
    
    @State private var selectedItem: PhotosPickerItem? = nil
    @State private var selectedImageData: Data? = nil
    
    var body: some View {
        
        PhotosPicker(
            selection: $selectedItem,
            matching: .images,
            photoLibrary: .shared()) {
                Text("Select a photo")
            }
            .onChange(of: selectedItem) { newItem in
                Task {
                    // Retrieve selected asset in the form of Data
                    if let data = try? await newItem?.loadTransferable(type: Data.self) {
                        selectedImageData = data
                    }
                }
            }
        
        if let selectedImageData,
           let uiImage = UIImage(data: selectedImageData) {
            Image(uiImage: uiImage)
                .resizable()
                .scaledToFit()
                .frame(width: 250, height: 250)
        }
    }
}

The Caveat

If you have watched the WWDC session about the PhotosPicker view, you will notice that the way we retrieve the selected image is a little bit different from what we saw in the video. Instead of loading it in the form of Image, we are loading it in the form of Data.

Retrieving selected image from photos picker in SwiftUI
Source: WWDC22 – What’s new in the Photos picker

As explained in this forum post, the Image type only supports public.png as its content type. If the photos picker contains assets of type other than png, such as jpeg or heic, we will not be able to retrieve it. Until Apple adds more content type support to Image, it is still advisable to use Data when retrieving images from the photos picker.


Wrapping Up

Throughout this article, I have been running the sample code on iOS, but in fact, the sample code will run totally fine on macOS, iPadOS, and watchOS.

According to Apple, the photos picker will automatically choose the best layout depending on the platform and the available screen space. This will definitely come out pretty handy for those who need to support multiple platforms.


If you enjoy reading this article, feel free to check out my other iOS development-related articles. You can also follow me on Twitter, and subscribe to my monthly newsletter.

Thanks for reading. 👨🏻‍💻


Further Readings


👋🏻 Hey!

While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.

  • Bartender: Superpower your menu bar and take full control over your menu bar items.
  • CleanShot X: The best screen capture app I’ve ever used.
  • PixelSnap: Measure on-screen elements with ease and precision.
  • iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.