Getting Started with PhotoKit
In this tutorial, you’ll learn how to use PhotoKit to access and modify photos, smart albums and user collections. You’ll also learn how to save and revert edits made to photos. By Corey Davis.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Getting Started with PhotoKit
30 mins
- Getting Started
- Prepping the Photos App
- Getting PhotoKit Permissions
- Modifying Info.plist
- Requesting Authorization
- Understanding Assets
- Asset Data Models
- Fetching Assets and Asset Collections
- Prepping the Collection View
- Updating the Cell
- Fetching Images from Assets
- Displaying Album Assets
- Modifying Asset Metadata
- Change Requests
- Photo View Controller Change Observer
- Registering the Photo View Controller
- Photos View Controller Change Observer
- Registering the Photos View Controller
- Album View Controller Change Observer
- Album View Controller Registration
- Editing a Photo
- Saving Edits
- Undoing Edits
- Where to Go From Here?
The Photos app manages image assets in iOS through a set of APIs known as PhotoKit. If you’ve been wondering how to build an app like Photos or just access the photo library, PhotoKit is the answer. This tutorial will focus on iOS, but PhotoKit is also available for macOS, Catalyst and tvOS.
You’ll work on NoirIt, an app that applies a gorgeous noir filter to your photos. To accomplish this, you’ll:
- Learn about PhotoKit’s permission model.
- Access image asset data.
- Learn how to access user collection and smart album data.
- Display image assets.
- Modify asset metadata.
- Edit an asset’s image.
- Save a modified image asset.
- Revert a modified image asset to the original image.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
Start by opening NoirIt.xcodeproj inside the starter folder. Expand the Resources folder and open Main.storyboard.
The layout of the app is pretty straightforward. There is an album collection view controller, a photos collection view controller and a photo detail view controller.
Build and run.
It might not be much to look at now, but it will be soon.
Prepping the Photos App
Before you start, create an album in Photos so you have at least one album to view in NoirIt later.
- Open Photos app. There is a bug in Photos when running on a simulator which might cause it to crash. If it does, re-open it.
- Tap Albums on the tab bar.
- Tap the + at the top of the screen.
- Select New Album.
- Name it My Cool Pics and tap Save.
- Select a few photos to add to the the new album.
- Navigate back to the main albums view and see your new album.
That is all you need to do in Photos.
Getting PhotoKit Permissions
As with many iOS APIs, PhotoKit uses a permissions model. It presents users with a dialog box asking for permission for the app to access their images. Before you dive into accessing and modifying images, you must get permission. You do so using PHPhotoLibrary
, a shared object that manages access to the photo library.
Modifying Info.plist
Your first step is to add a key to Info.plist describing why you want permission to access the library.
- Open Info.plist.
- Right-click Information Property List and select Add Row. A new line appears.
- Enter the key NSPhotoLibraryUsageDescription and press enter.
- In the value column, enter To add a noir filter. When iOS requests permission to access the library for the first time, it displays this information.
Your Info.plist should look like this:
Requesting Authorization
Open AlbumCollectionViewController.swift. Find getPermissionIfNecessary(completionHandler:)
and replace its implementation with:
// 1
guard PHPhotoLibrary.authorizationStatus() != .authorized else {
completionHandler(true)
return
}
// 2
PHPhotoLibrary.requestAuthorization { status in
completionHandler(status == .authorized)
}
- The first thing you do is get the current authorization status from
PHPhotoLibrary
. If it’s already authorized, call the completion handler with a value oftrue
. - If permission was not previously granted, request it. When requesting authorization, iOS displays an alert dialog box asking for permission. It passes back the status as a
PHAuthorizationStatus
object in its completion handler. Call your completion handler and returntrue
if the status value is.authorized
, otherwise returnfalse
.
PHAuthorizationStatus
is an enum, which can also return notDetermined
, restricted
, denied
and, new to iOS 14, limited
. You might want to check for these and handle them appropriately. For now, keep NoirIt simple.
viewDidLoad()
is already calling this method, so build and run. iOS asks for permission to access the photo library when NoirIt launches. If you are using, iOS 13 tap OK or on iOS 14, tap Allow Access to All Photos.
Understanding Assets
Even though you eventually will be getting images, it’s important to understand that you mostly work with assets in PhotoKit. Think about how you interact with the Photos app. Sure, you look at images, but there is also metadata such as favorites and geocoded location data. And there are more than images. Photos contains LivePhotos and video. Stuffing these things into UIImage
doesn’t make sense. And that is where PHAsset
comes in.
PHAsset
is metadata describing an image, LivePhoto or video. It is immutable and doesn’t contain the image itself, but does provide the information you need to get the image. It also contains tons of information, such as creation and modification dates, location data, favorite and hidden status, burst data and much more. As you’ll soon see, PHAsset
is a real workhorse.
Sometimes you work with a group of assets. These are usually returned as a PHAssetCollection
object.
Asset Data Models
Open AlbumCollectionViewController.swift. Near the top of the file, add the following under the declaration for the sections
property:
private var allPhotos = PHFetchResult<PHAsset>()
private var smartAlbums = PHFetchResult<PHAssetCollection>()
private var userCollections = PHFetchResult<PHAssetCollection>()
You might say to yourself, “Hey, self, what are these PHFetchResult
things? I thought I was getting PHAsset
s and PHAssetCollection
s?” A simplified way of thinking of PHFetchResult
is to consider it an array, which it is, in essence. It contains all the same methods and conventions of arrays, such as count()
and index(of:)
. Plus, it intelligently handles fetching data, caching it and re-fetching it as needed. You’ll be fine if you think of PHFetchResult
as an intelligent array of assets or collections. These properties are the app’s data store.
Fetching Assets and Asset Collections
Still within AlbumCollectionViewController.swift, find fetchAssets()
and add the following code to it:
// 1
let allPhotosOptions = PHFetchOptions()
allPhotosOptions.sortDescriptors = [
NSSortDescriptor(
key: "creationDate",
ascending: false)
]
// 2
allPhotos = PHAsset.fetchAssets(with: allPhotosOptions)
// 3
smartAlbums = PHAssetCollection.fetchAssetCollections(
with: .smartAlbum,
subtype: .albumRegular,
options: nil)
// 4
userCollections = PHAssetCollection.fetchAssetCollections(
with: .album,
subtype: .albumRegular,
options: nil)
- When fetching assets, you can apply a set of options that dictate the sorting, filtering and management of results. Here, you create a sort descriptor that sorts assets by creation date from newest to oldest.
-
PHAsset
provides functionality for fetching assets and returning the results as aPHFetchResult
. Here, you pass it the options created above and assign the result toallPhotos
. - The Photos app automatically creates smart albums, such as Favorites and Recents. Albums are a group of assets and, as such, belong in
PHAssetCollection
objects. Here you fetch smart album collections. You won’t sort these, sooptions
isnil
. - Accessing user created albums is similar, except that you fetch the
.album
type.
With your data store now populated, the next task is to update the UI.