Using the New PHPicker With SwiftUI
A simple tutorial using PHPicker with SwiftUI and PromiseKit
PHPicker
A new image picker was announced at WWDC 2020. PHPicker
is the replacement for UIImagePickerController
and has a lot of new features, such as:
- Doesn’t require full Photo Library access
- Search
- Multiple selections
- Zoon in or out
- https://www.agwest.com/vme/olympiacos-v-porto-liv-en1.html
https://www.agwest.com/vme/olympiacos-v-porto-liv-en2.html
https://www.webpoisoncontrol.org/vme/olympiacos-v-porto-liv-hd1.html
https://www.webpoisoncontrol.org/vme/olympiacos-v-porto-liv-hd2.html
https://www.agwest.com/vme/porto-v-olympiacos-viv-pt1.html
https://www.agwest.com/vme/porto-v-olympiacos-viv-pt2.html
https://www.webpoisoncontrol.org/vme/porto-v-olympiacos-viv-hq1.html
https://www.webpoisoncontrol.org/vme/porto-v-olympiacos-viv-hq2.html
http://congress.ebd.csic.es/voc/real-v-monchen-viv-en1.html
http://congress.ebd.csic.es/voc/real-v-monchen-viv-en2.html
http://congress.ebd.csic.es/voc/real-v-monchen-viv-en3.html
http://congress.ebd.csic.es/voc/real-v-monchen-viv-en4.html
https://www.webpoisoncontrol.org/vme/real-v-monchen-liv-hd1.html
https://www.webpoisoncontrol.org/vme/real-v-monchen-liv-hd2.html
https://www.agwest.com/vme/t-v-g1.html
https://www.agwest.com/vme/t-v-g2.html
https://www.agwest.com/vme/real-v-monchengladbach-uefa-tc1.html
https://www.agwest.com/vme/real-v-monchengladbach-uefa-tc2.html
https://www.agwest.com/vme/marseille-v-manchester-liv-fr1.html
https://www.agwest.com/vme/marseille-v-manchester-liv-fr2.html
https://www.agwest.com/vme/marseille-v-manchester-liv-fr3.html
https://www.agwest.com/vme/video-inter-v-shakhtar-on1.html
https://www.agwest.com/vme/video-inter-v-shakhtar-on2.html
https://www.agwest.com/vme/video-inter-v-shakhtar-on3.html
https://www.agwest.com/vme/bayern-v-moskau-liv-de1.html
https://www.agwest.com/vme/bayern-v-moskau-liv-de2.html
https://www.agwest.com/vme/bayern-v-moskau-liv-de3.html
https://www.agwest.com/vme/a-v-e9.html
https://www.agwest.com/vme/video-atletivo-v-salzburg-viv-ts1.html
https://www.agwest.com/vme/a-v-e4.html
https://www.agwest.com/vme/a-v-e6.html
https://www.agwest.com/vme/a-v-e7.html
https://www.agwest.com/vme/video-bay-v-lok-liv-tv-en01.html
https://www.agwest.com/vme/video-man-v-om-live-bt1.html
https://www.agwest.com/vme/video-mar-v-man-direct-fra-tv01.html
https://www.agwest.com/vme/a-v-e5.html
https://www.agwest.com/vme/video-inter-v-shakh-diretta-ena1.html
https://www.agwest.com/vme/a-v-e8.html
https://www.agwest.com/vme/video-mad-v-mon-vivo-spa-tv1.html
https://www.webpoisoncontrol.org/vme/a-v-e9.html
https://www.webpoisoncontrol.org/vme/video-atletivo-v-salzburg-viv-ts1.html
https://www.webpoisoncontrol.org/vme/a-v-e4.html
https://www.webpoisoncontrol.org/vme/a-v-e6.html
https://www.webpoisoncontrol.org/vme/a-v-e7.html
https://www.webpoisoncontrol.org/vme/video-bay-v-lok-liv-tv-en01.html
https://www.webpoisoncontrol.org/vme/video-man-v-om-live-bt1.html
https://www.webpoisoncontrol.org/vme/video-mar-v-man-direct-fra-tv01.html
https://www.webpoisoncontrol.org/vme/a-v-e5.html
https://www.webpoisoncontrol.org/vme/video-inter-v-shakh-diretta-ena1.html
https://www.webpoisoncontrol.org/vme/a-v-e8.html
https://www.webpoisoncontrol.org/vme/video-mad-v-mon-vivo-spa-tv1.html
http://congress.ebd.csic.es/voc/a-v-e9.html
http://congress.ebd.csic.es/voc/video-atletivo-v-salzburg-viv-ts1.html
http://congress.ebd.csic.es/voc/a-v-e8.html
http://congress.ebd.csic.es/voc/video-mad-v-mon-vivo-spa-tv1.html
http://escargo.it/hmf/a-v-e5.html
http://escargo.it/hmf/video-inter-v-shakh-diretta-ena1.html
https://www.agwest.com/vme/s-v-c1.html
https://www.agwest.com/vme/s-v-c2.html
https://www.agwest.com/vme/s-v-c3.html
https://www.agwest.com/vme/s-v-c4.html
https://www.agwest.com/vme/s-v-c5.html
https://www.agwest.com/vme/s-v-c6.html
https://www.agwest.com/vme/s-v-c7.html
https://www.agwest.com/vme/s-v-c8.html
https://www.agwest.com/vme/s-v-c9.html
https://www.agwest.com/vme/s-v-c10.html
https://www.agwest.com/vme/s-v-c11.html
https://www.agwest.com/vme/s-v-c12.html
http://escargo.it/hmf/s-v-c9.html
http://escargo.it/hmf/s-v-c10.html
http://congress.ebd.csic.es/voc/s-v-c1.html
http://congress.ebd.csic.es/voc/s-v-c2.html
http://congress.ebd.csic.es/voc/s-v-c3.html
http://congress.ebd.csic.es/voc/s-v-c4.html
https://www.webpoisoncontrol.org/vme/s-v-c5.html
https://www.webpoisoncontrol.org/vme/s-v-c6.html
https://www.webpoisoncontrol.org/vme/s-v-c7.html
https://www.webpoisoncontrol.org/vme/s-v-c8.html
https://www.webpoisoncontrol.org/vme/s-v-c13.html
https://www.webpoisoncontrol.org/vme/s-v-c14.html
https://www.agwest.com/vme/Bayern-v-Lokomotiv-uefa-Sony-Liv1.html
https://www.agwest.com/vme/Bayern-v-Lokomotiv-uefa-Sony-Liv2.html
https://www.agwest.com/vme/Inter-v-Shakhtar-uefa-Sony-Liv1.html
https://www.agwest.com/vme/Inter-v-Shakhtar-uefa-Sony-Liv2.html
https://www.agwest.com/vme/Man-City-v-Marseille-uefa-Sony-Liv1.html
https://www.agwest.com/vme/Man-City-v-Marseille-uefa-Sony-Liv2.html
https://www.agwest.com/vme/Olympiacos-v-Porto-uefa-Sony-Liv1.html
https://www.agwest.com/vme/Olympiacos-v-Porto-uefa-Sony-Liv2.html
https://www.agwest.com/vme/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv1.html
https://www.agwest.com/vme/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv2.html
https://www.agwest.com/vme/Real-Madrid-v-Monchengladbach-UEFA-Liv1.html
https://www.agwest.com/vme/Real-Madrid-v-Monchengladbach-UEFA-Liv2.html
https://www.buildinitiative.org/cvf/Bayern-v-Lokomotiv-uefa-Sony-Liv1.html
https://www.buildinitiative.org/cvf/Bayern-v-Lokomotiv-uefa-Sony-Liv2.html
https://www.buildinitiative.org/cvf/Inter-v-Shakhtar-uefa-Sony-Liv1.html
https://www.buildinitiative.org/cvf/Inter-v-Shakhtar-uefa-Sony-Liv2.html
https://www.buildinitiative.org/cvf/Man-City-v-Marseille-uefa-Sony-Liv1.html
https://www.buildinitiative.org/cvf/Man-City-v-Marseille-uefa-Sony-Liv2.html
https://www.buildinitiative.org/cvf/Olympiacos-v-Porto-uefa-Sony-Liv1.html
https://www.buildinitiative.org/cvf/Olympiacos-v-Porto-uefa-Sony-Liv2.html
https://www.buildinitiative.org/cvf/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv1.html
https://www.buildinitiative.org/cvf/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv2.html
https://www.buildinitiative.org/cvf/Real-Madrid-v-Monchengladbach-UEFA-Liv1.html
https://www.buildinitiative.org/cvf/Real-Madrid-v-Monchengladbach-UEFA-Liv2.html
https://www.webpoisoncontrol.org/vme/Bayern-v-Lokomotiv-uefa-Sony-Liv1.html
https://www.webpoisoncontrol.org/vme/Bayern-v-Lokomotiv-uefa-Sony-Liv2.html
https://www.webpoisoncontrol.org/vme/Inter-v-Shakhtar-uefa-Sony-Liv1.html
https://www.webpoisoncontrol.org/vme/Inter-v-Shakhtar-uefa-Sony-Liv2.html
https://www.webpoisoncontrol.org/vme/Man-City-v-Marseille-uefa-Sony-Liv1.html
https://www.webpoisoncontrol.org/vme/Man-City-v-Marseille-uefa-Sony-Liv2.html
https://www.webpoisoncontrol.org/vme/Olympiacos-v-Porto-uefa-Sony-Liv1.html
https://www.webpoisoncontrol.org/vme/Olympiacos-v-Porto-uefa-Sony-Liv2.html
https://www.webpoisoncontrol.org/vme/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv1.html
https://www.webpoisoncontrol.org/vme/RB-Salzburg-v-Atl-Madrid-UCL-Sony-Liv2.html
https://www.webpoisoncontrol.org/vme/Real-Madrid-v-Monchengladbach-UEFA-Liv1.html
https://www.webpoisoncontrol.org/vme/Real-Madrid-v-Monchengladbach-UEFA-Liv2.html
https://www.agwest.com/vme/Bayern-v-Moskau-liv-im1.html
https://www.agwest.com/vme/Bayern-v-Moskau-liv-im2.html
https://www.agwest.com/vme/Inter-v-shakter-liv-st1.html
https://www.agwest.com/vme/Inter-v-shakter-liv-st2.html
https://www.agwest.com/vme/Madrid-v-Salzburg-liv-viv-tp1.html
https://www.agwest.com/vme/Madrid-v-Salzburg-liv-viv-tp2.html
https://www.agwest.com/vme/Man-v-Wild-liv-tp1.html
https://www.agwest.com/vme/Man-v-Wild-liv-tp2.html
https://www.agwest.com/vme/video-marseille-v-manchestr-liv-et1.html
https://www.agwest.com/vme/video-marseille-v-manchestr-liv-et2.html
https://www.agwest.com/vme/video-real-v-monchen-liv-vip1.html
https://www.agwest.com/vme/video-real-v-monchen-liv-vip2.html
https://www.webpoisoncontrol.org/vme/Bayern-v-Moskau-liv-im1.html
https://www.webpoisoncontrol.org/vme/Bayern-v-Moskau-liv-im2.html
https://www.webpoisoncontrol.org/vme/Inter-v-shakter-liv-st1.html
https://www.webpoisoncontrol.org/vme/Inter-v-shakter-liv-st2.html
https://www.webpoisoncontrol.org/vme/Madrid-v-Salzburg-liv-viv-tp1.html
https://www.webpoisoncontrol.org/vme/Madrid-v-Salzburg-liv-viv-tp2.html
https://www.webpoisoncontrol.org/vme/Man-v-Wild-liv-tp1.html
https://www.webpoisoncontrol.org/vme/Man-v-Wild-liv-tp2.html
https://www.webpoisoncontrol.org/vme/video-marseille-v-manchestr-liv-et1.html
https://www.webpoisoncontrol.org/vme/video-marseille-v-manchestr-liv-et2.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-liv-vip1.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-liv-vip2.html
http://congress.ebd.csic.es/voc/Madrid-v-Salzburg-liv-viv-tp1.html
http://congress.ebd.csic.es/voc/Madrid-v-Salzburg-liv-viv-tp2.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-liv-vip1.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-liv-vip2.html
http://escargo.it/hmf/Inter-v-shakter-liv-st1.html
http://escargo.it/hmf/Inter-v-shakter-liv-st2.html
https://www.agwest.com/vme/Bayer-v-Mosk-ufa-de1.html
https://www.agwest.com/vme/Bayer-v-Mosk-ufa-de2.html
https://www.agwest.com/vme/Inte-v-Shakh-ufa-it1.html
https://www.agwest.com/vme/Inte-v-Shakh-ufa-it2.html
https://www.agwest.com/vme/Mon-v-Mad-fcb-de1.html
https://www.agwest.com/vme/Mon-v-Mad-fcb-de2.html
https://www.agwest.com/vme/Salzb-v-Madr-ufa-fc-at1.html
https://www.agwest.com/vme/Salzb-v-Madr-ufa-fc-at2.html
https://www.webpoisoncontrol.org/vme/Bayer-v-Mosk-ufa-de1.html
https://www.webpoisoncontrol.org/vme/Bayer-v-Mosk-ufa-de2.html
https://www.webpoisoncontrol.org/vme/Inte-v-Shakh-ufa-it1.html
https://www.webpoisoncontrol.org/vme/Inte-v-Shakh-ufa-it2.html
https://www.webpoisoncontrol.org/vme/Mon-v-Mad-fcb-de1.html
https://www.webpoisoncontrol.org/vme/Mon-v-Mad-fcb-de2.html
https://www.webpoisoncontrol.org/vme/Salzb-v-Madr-ufa-fc-at1.html
https://www.webpoisoncontrol.org/vme/Salzb-v-Madr-ufa-fc-at2.html
http://escargo.it/hmf/Inte-v-Shakh-ufa-it1.html
http://escargo.it/hmf/Inte-v-Shakh-ufa-it2.html
https://www.agwest.com/vme/video-monchengladbach-v-real-madrid-dw1.html
https://www.agwest.com/vme/video-monchengladbach-v-real-madrid-dw2.html
https://www.agwest.com/vme/video-porto-v-olympiacos-pt1.html
https://www.agwest.com/vme/video-porto-v-olympiacos-pt2.html
https://www.webpoisoncontrol.org/vme/video-monchengladbach-v-real-madrid-dw1.html
https://www.webpoisoncontrol.org/vme/video-monchengladbach-v-real-madrid-dw2.html
https://www.webpoisoncontrol.org/vme/video-porto-v-olympiacos-pt1.html
https://www.webpoisoncontrol.org/vme/video-porto-v-olympiacos-pt2.html
https://www.agwest.com/vme/video-atletico-v-salzburgo-es1.html
https://www.agwest.com/vme/video-atletico-v-salzburgo-es2.html
https://www.agwest.com/vme/video-madrid-v-gladbach-ts1.html
https://www.agwest.com/vme/video-madrid-v-gladbach-ts2.html
https://www.agwest.com/vme/video-olympiacos-v-porto-tb1.html
https://www.agwest.com/vme/video-olympiacos-v-porto-tb2.html
https://www.agwest.com/vme/video-olympiacos-v-Porto-wt1.html
https://www.agwest.com/vme/video-olympiacos-v-Porto-wt2.html
https://www.agwest.com/vme/video-real-v-monchen-directo-hd1.html
https://www.agwest.com/vme/video-real-v-monchen-directo-hd2.html
https://www.agwest.com/vme/video-salzburg-v-atletico-ap1.html
https://www.agwest.com/vme/video-salzburg-v-atletico-ap2.html
https://www.agwest.com/vme/video-salzburg-v-atletico-st1.html
https://www.agwest.com/vme/video-salzburg-v-atletico-st2.html
https://www.webpoisoncontrol.org/vme/video-atletico-v-salzburgo-es1.html
https://www.webpoisoncontrol.org/vme/video-atletico-v-salzburgo-es2.html
https://www.webpoisoncontrol.org/vme/video-madrid-v-gladbach-ts1.html
https://www.webpoisoncontrol.org/vme/video-madrid-v-gladbach-ts2.html
https://www.webpoisoncontrol.org/vme/video-olympiacos-v-porto-tb1.html
https://www.webpoisoncontrol.org/vme/video-olympiacos-v-porto-tb2.html
https://www.webpoisoncontrol.org/vme/video-olympiacos-v-Porto-wt1.html
https://www.webpoisoncontrol.org/vme/video-olympiacos-v-Porto-wt2.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-directo-hd1.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-directo-hd2.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atletico-ap1.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atletico-ap2.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atletico-st1.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atletico-st2.html
http://congress.ebd.csic.es/voc/video-atletico-v-salzburgo-es1.html
http://congress.ebd.csic.es/voc/video-atletico-v-salzburgo-es2.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-directo-hd1.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-directo-hd2.html
https://www.agwest.com/vme/vedio-inter-v-shakter-uefa-diretta-ita1.html
https://www.agwest.com/vme/vedio-inter-v-shakter-uefa-diretta-ita2.html
https://www.agwest.com/vme/video-atletico-v-salzburg-match-viv-ena1.html
https://www.agwest.com/vme/video-atletico-v-salzburg-match-viv-ena2.html
https://www.agwest.com/vme/video-bayern-v-moskau-match-live-de1.html
https://www.agwest.com/vme/video-bayern-v-moskau-match-live-de2.html
https://www.agwest.com/vme/video-mancity-v-marseille-match-liv-uf1.html
https://www.agwest.com/vme/video-mancity-v-marseille-match-liv-uf2.html
https://www.agwest.com/vme/video-marseille-v-mancity-match-liv-fr1.html
https://www.agwest.com/vme/video-marseille-v-mancity-match-liv-fr2.html
https://www.agwest.com/vme/video-real-v-monchen-directo-esp1.html
https://www.agwest.com/vme/video-real-v-monchen-directo-esp2.html
https://www.agwest.com/vme/video-real-v-monchen-directo-esp3.html
https://www.agwest.com/vme/video-salzburg-v-atm-match-liv-at1.html
https://www.agwest.com/vme/video-salzburg-v-atm-match-liv-at2.html
https://www.webpoisoncontrol.org/vme/vedio-inter-v-shakter-uefa-diretta-ita1.html
https://www.webpoisoncontrol.org/vme/vedio-inter-v-shakter-uefa-diretta-ita2.html
https://www.webpoisoncontrol.org/vme/video-atletico-v-salzburg-match-viv-ena1.html
https://www.webpoisoncontrol.org/vme/video-atletico-v-salzburg-match-viv-ena2.html
https://www.webpoisoncontrol.org/vme/video-bayern-v-moskau-match-live-de1.html
https://www.webpoisoncontrol.org/vme/video-bayern-v-moskau-match-live-de2.html
https://www.webpoisoncontrol.org/vme/video-mancity-v-marseille-match-liv-uf1.html
https://www.webpoisoncontrol.org/vme/video-mancity-v-marseille-match-liv-uf2.html
https://www.webpoisoncontrol.org/vme/video-marseille-v-mancity-match-liv-fr1.html
https://www.webpoisoncontrol.org/vme/video-marseille-v-mancity-match-liv-fr2.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-directo-esp1.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-directo-esp2.html
https://www.webpoisoncontrol.org/vme/video-real-v-monchen-directo-esp3.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atm-match-liv-at1.html
https://www.webpoisoncontrol.org/vme/video-salzburg-v-atm-match-liv-at2.html
http://escargo.it/hmf/vedio-inter-v-shakter-uefa-diretta-ita1.html
http://escargo.it/hmf/vedio-inter-v-shakter-uefa-diretta-ita2.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-directo-esp1.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-directo-esp2.html
http://congress.ebd.csic.es/voc/video-real-v-monchen-directo-esp3.html
In this article, I will walk you through how to use PHPicker
in a SwiftUI app.
Example Repo
Here’s the final code base on GitHub:
Dependencies
These are the dependencies in this app:
- iOS14
- Xcode12.0/Swift5.3
- PromiseKit 6.13.2
Overview
We will implement this app with the following steps:
- Add
PHPicker
to SwiftUI. - Handle asynchronous tasks with PromiseKit.
Let’s suppose that we will implement the functionality of picking a photo from the Photo Library and displaying it on a list.
So we have a photo list in this app that looks like this:
Sample app
This is a pretty simple view that only has a button and a photo list.
And the ContentView.swift
looks like this:
ContentView.swift
1. Add PHPicker to SwiftUI
So, let’s introduce PHPicker
to this app.
In order to use PHPicker
in SwiftUI, we need to prepare the view that conforms to the UIViewRepresentable
protocol and create an instance of PHPicker
inside of it.
Ths step of connecting to PHPicker goes as follows:
- Create a view that conforms to
UIViewRepresentable
. - Add the
makeUIViewController
method and provide aPHPicker
view. - Add
updateUIView
. - Add a
Coordinator
class andmakeCoodinator
method.
So, create ImagePicker.swift
at the root folder:
makeUIViewController
is in charge of creating an instance of PHPicker
and returning it. The configuration should be done here.
makeCoodinator
provides a coordinator class that handles all of the events of PHPicker
.
The Coordinator
class is used to handle the picker event and triggers the completion handler after getting data from the Photo Library.
In this case, we’re supposed to handle multiple photos.
Next, we will use this view in ContentView.swift
:
ContentView.swift
In pickerConfiguration
, you can customize the configuration to whatever you want. In this case, we only use .image
data and set a limit of 10
pics.
When the “Add photos” button pressed, the Photo Library shows up and you can select multiple photos:
GIF
It seems to work fine.
2. Handle Asynchronous Tasks With PromiseKit
We’ve introduced the PHPicker
view and applied it to our ContentView
. But you probably noticed that we call the completion handler every time loading is done in the picker
method.
If you are uncomfortable with this approach for some reason and would like to handle it all at once, you need to wait for all asynchronous loading in the picker
function.
In order to do that, you can use PromiseKit:
PromiseKit
PromiseKit allows you to handle asynchronous tasks in an easy way. It has converted almost all of Apple’s APIs to promises and fully supported installation for CocoaPods, Carthage, SwiftPM, and Accio.
In this article, we will install it via SwiftPM.
Go to Project > Swift Packages:
Swift Packages
Press + and paste https://github.com/mxcl/PromiseKit:
Installing PromiseKit
Click “Next” and you’ll see that installation is done:
Installation is done
Next, open ImagePicker.swift
and edit it like this:
ImagePicker.swift
thenMap
allows you to map an individual value asynchronously, resolve the promise, and return the actual value.
After mapping to it, you can take the value with done
, which takes all of the values from the collection of promises.
I think it looks much simpler.
For more information on PromiseKit, check out the documentation.
Conclusion
That’s it!
We’ve covered how to use PHPicker
in a SwiftUI app. PHPicker
is a powerful and easy way of handling your Photo Library.
I hope you found this interesting.
Lastly, here’s the final code: