Swift 使用async/await实现一句代码获取系统相册照片和视频

语言: CN / TW / HK

众所周知,想要获取系统相册照片和视频,也就是调起UIImagePickerController,创建控制器、遵守代理、实现代理方法、弹出/关闭控制器,拿张照片都如此繁琐。为了更快获取系统相册照片和视频,于是封装了一个系统相册的工具类ImagePicker,内部实现好代理和弹出/关闭的操作,方便自己平时调试。

Demo地址

  • 🌰ImagePicker封装的方法其一:打开相册,通过闭包返回照片图片: swift func getPhoto() { ImagePicker.openAlbumForImage { [weak self] result in guard let self = self else { return } switch result { case let .success(image): self.setupImage(image) case let .failure(pickError): pickError.log() } } }

这么一看好像已经够简洁了,不过Swift现在已经有async/await的特性了,那是不是可以通过一句代码就能获取到图片呢?

答案是肯定可以的啦。

Swift中的async/await代码实例详解这篇文章中得知,可以通过withCheckedThrowingContinuation将【基于闭包异步处理结果】转换成【结构化并发同步处理结果】,实现一句代码获取系统相册照片: swift func getPhoto() async { let image: UIImage? = try? await ImagePicker.openAlbum() imgView.image = image } 这样看上去就真的超简洁了~

  • 主要实现方式: ```swift // MARK: - Pick object handle private extension ImagePicker.Controller { // 以前的方式: // - 保存闭包,直至代理方法的调起,然后通过该闭包以返回结果 // - 外部调用:picker.pickObject() { result in ...... },通过闭包异步获取结果 func pickObject(completion: @escaping ImagePicker.Completion) { self.completion = completion }

    // 现在的方式: // - 通过withCheckedThrowingContinuation将【基于闭包异步处理结果】转换成【结构化并发同步处理结果】 // - 外部调用:let object: T? = try? await picker.pickObject(),等待并同步获取结果 func pickObject() async throws -> T { try await withCheckedThrowingContinuation { continuation in // 在以前的方式中这个闭包是给外部使用的,现在的方式修改成【内部使用】:             // 外部先卡住函数,等待代理方法的调起,然后通过continuation将结果返回给外部,实现同步处理。 pickObject() { result in continuation.resume(with: result) } } }

    // MARK: - UIImagePickerControllerDelegate // 用户选择了照片/视频 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { // 1.获取结果 let result: Result do { result = .success(try T.fetchFromPicker(info)) } catch let pickError as ImagePicker.PickError { result = .failure(pickError) } catch { result = .failure(.other(error)) }

    // 2.返回结果
    completion?(result)
    
    // 3.关闭控制器
    dismiss(animated: true)
    

    }

    // 用户点击了取消 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { // 1.返回结果:用户点击取消 completion?(.failure(.userCancel))

    // 2.关闭控制器
    dismiss(animated: true)
    

    } } ```

  • 通过泛型和重载的特性扩展一下,返回更多类型: ```swift // 相册 -> 图片 let image: UIImage? = try? await ImagePicker.openAlbum()

// 相册 -> 二进制数据(图片、GIF) let imageData: Data? = try? await ImagePicker.openAlbum()

// 相册 -> 视频路径 let videoURL: URL? = try? await ImagePicker.openAlbum()

// 拍照 -> 图片 let image: UIImage? = try? await ImagePicker.photograph() `` PS:当然啦,肯定会有拿不到的情况,所有失败的场景我都使用了ImagePicker.PickError抛出,可通过do {} catch {}`捕获。

至此,封装的ImagePicker可以很方便地让我获取系统相册的照片和视频。 不过获取相册数据一般都会用第三方库来做,我这个工具类只是更多的用来平时的调试,最主要是熟悉一下async/await的特性。

OK,本文就到此为止,祝大家新年快乐~

Demo地址