Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Day 64: Project 13: Instafilter (Part Three)

Follow along at https://www.hackingwithswift.com/100/swiftui/64.


📒 Field Notes

This day covers Part Three of Project 13: Instafilter in the 100 Days of SwiftUI Challenge. (Project 13 files can be found in the directory for Part One.)

It focuses on several specific topics:

  • Using coordinators to manage SwiftUI view controllers
  • How to save images to the user’s photo library

How to save images to the user’s photo library

We could use the super-archaic UIImageWriteToSavedPhotosAlbum method -- or we can take advantage of PhotoKit's PHPhotoLibrary class, which offers a number of utilities for creating and saving images assets that don't rely on passing UnsafeRawPointers around 😆.

Even better, we can wrap our PHPhotoLibrary calls in Combine Futures that can be resolved in other @ObservableObjects -- creating reactive streams that update according to how an operation turned out.

import Foundation
import UIKit
import Combine
import Photos


enum ImageWriter {
    static let defaultQueue = DispatchQueue(label: "Image Writer", qos: .userInitiated)

    enum Error: Swift.Error, Identifiable {
        var id: String { self.localizedDescription }

        case failedToCreateAsset
        case genericWritingError(Swift.Error)
    }


    static func write(
        imageToPhotoAlbum image: UIImage,
        on queue: DispatchQueue = defaultQueue
    ) -> Future<String, ImageWriter.Error> {
        Future { resolve in
            queue.async {
                do {
                    try PHPhotoLibrary.shared().performChangesAndWait {
                        let creationRequest = PHAssetCreationRequest.creationRequestForAsset(from: image)

                        guard let savedAssetID = creationRequest.placeholderForCreatedAsset?.localIdentifier else {
                            return resolve(.failure(.failedToCreateAsset))
                        }

                        resolve(.success(savedAssetID))
                    }
                } catch {
                    resolve(.failure(.genericWritingError(error)))
                }
            }
        }
    }
}