Swift 使用async/await實現(xiàn)一句代碼獲取系統(tǒng)相冊照片和視頻

眾所周知,想要獲取系統(tǒng)相冊照片和視頻,也就是調(diào)起UIImagePickerController,創(chuàng)建控制器、遵守代理、實現(xiàn)代理方法、彈出/關(guān)閉控制器,拿張照片都如此繁瑣。為了更快獲取系統(tǒng)相冊照片和視頻,于是封裝了一個系統(tǒng)相冊的工具類ImagePicker,內(nèi)部實現(xiàn)好代理和彈出/關(guān)閉的操作,方便自己平時調(diào)試。

Demo地址

  • ??ImagePicker封裝的方法其一:打開相冊,通過閉包返回照片圖片:
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()
        }
    }
}

這么一看好像已經(jīng)夠簡潔了,不過Swift現(xiàn)在已經(jīng)有async/await的特性了,那是不是可以通過一句代碼就能獲取到圖片呢?

答案是肯定可以的啦。

Swift中的async/await代碼實例詳解這篇文章中得知,可以通過withCheckedThrowingContinuation將【基于閉包異步處理結(jié)果】轉(zhuǎn)換成【結(jié)構(gòu)化并發(fā)同步處理結(jié)果】,實現(xiàn)一句代碼獲取系統(tǒng)相冊照片:

func getPhoto() async {
    let image: UIImage? = try? await ImagePicker.openAlbum()
    imgView.image = image
}

這樣看上去就真的超簡潔了~

  • 主要實現(xiàn)方式:
// MARK: - Pick object handle
private extension ImagePicker.Controller {
    // 以前的方式:
    // - 保存閉包,直至代理方法的調(diào)起,然后通過該閉包以返回結(jié)果
    // - 外部調(diào)用:picker.pickObject() { result in ...... },通過閉包異步獲取結(jié)果
    func pickObject(completion: @escaping ImagePicker.Completion<T>) {
        self.completion = completion
    }
    
    // 現(xiàn)在的方式:
    // - 通過`withCheckedThrowingContinuation`將【基于閉包異步處理結(jié)果】轉(zhuǎn)換成【結(jié)構(gòu)化并發(fā)同步處理結(jié)果】
    // - 外部調(diào)用:let object: T? = try? await picker.pickObject(),等待并同步獲取結(jié)果
    func pickObject() async throws -> T {
        try await withCheckedThrowingContinuation { continuation in
            // 在以前的方式中這個閉包是給外部使用的,現(xiàn)在的方式修改成【內(nèi)部使用】:
            // 外部先卡住函數(shù),等待代理方法的調(diào)起,然后通過`continuation`將結(jié)果返回給外部,實現(xiàn)同步處理。
            pickObject() { result in
                continuation.resume(with: result)
            }
        }
    }
    
    // MARK: - UIImagePickerControllerDelegate
    // 用戶選擇了照片/視頻
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // 1.獲取結(jié)果
        let result: Result<T, ImagePicker.PickError>
        do {
            result = .success(try T.fetchFromPicker(info))
        } catch let pickError as ImagePicker.PickError {
            result = .failure(pickError)
        } catch {
            result = .failure(.other(error))
        }
        
        // 2.返回結(jié)果
        completion?(result)
        
        // 3.關(guān)閉控制器
        dismiss(animated: true)
    }
    
    // 用戶點擊了取消
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // 1.返回結(jié)果:用戶點擊取消
        completion?(.failure(.userCancel))
        
        // 2.關(guān)閉控制器
        dismiss(animated: true)
    }
}
  • 通過泛型和重載的特性擴展一下,返回更多類型:
// 相冊 -> 圖片
let image: UIImage? = try? await ImagePicker.openAlbum()

// 相冊 -> 二進制數(shù)據(jù)(圖片、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可以很方便地讓我獲取系統(tǒng)相冊的照片和視頻。
不過獲取相冊數(shù)據(jù)一般都會用第三方庫來做,我這個工具類只是更多的用來平時的調(diào)試,最主要是熟悉一下async/await的特性。

OK,本文就到此為止,祝大家新年快樂~

Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容