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地址