PromisKit使用

PromiseKit是为了解决Swift中异步回调地狱问题的库,通过Promise的创建和链式调用来提高代码的可读性和结构清晰度。本文介绍了如何创建Promise,包括有错误处理和无错误处理的情况,以及Promise链的构建。还涉及到自定义回调线程、延迟、超时和重试等高级用法,帮助开发者更好地管理和组织异步任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

promistKit主要是解决异步回调地狱的问题,举个例子,比如需要下载一个图片文件,而且这个图片文件的下载链接也需要请求,也就是先请求一个接口然后图片的下载链接,然后通过该链接去下载图片,普通做法大概就是这样:


URLSession.shared.dataTask(with: backendurl!) { data, _, error in
    if error != nil {
        print(error)
        return
    }
    
    let imageurl = String(data: data!, encoding: String.Encoding.utf8) as String! 
    
    URLSession.shared.dataTask(with: URL(string:imageurl!)!) { (data, response, error) in
        if error != nil {
            print(error)
            return
        }
        DispatchQueue.main.async {
            imageView.image = UIImage(data: data!)
        }
    }.resume()
}.resume()

如果再有其他操作,一层嵌套一层 的网络请求,结构很不清晰很不具有阅读性,而PromiseKit的出现就很好的解决了这个问题

Promise创建

promise包含两个回调闭包,当任务完成可以使用fulfill来回调成功信息,也可以使用reject来回调错误信息

Promise() { fulfill, reject in
    // code       
}

比如下载一个图片的请求可以这样做

func fetch(url: URL) -> Promise<Data> {
    return Promise { seal in
        URLSession.shared.dataTask(with: url!) { data, _, error in
            seal.resolve(data, error)
        }.resume()
    }
}

当然在编程过程中也不是总会有处理错误信息的时候,可以用Guarantee创建一个没有错误信息的

Guarantee { seal in
    seal("Hello World")
}.done {
            print($0)
        }

Promise 链

then(),done(),catch()

上面我们创建了一个图片下载的promise请求,然后我们可以使用then()函数来链接,

fetch(url: <backend-url>).then { value in
    // value
}

then()需要返回一个Promise,以此一直then,可以用done()来结束调用链,用catch()来捕获错误信息

fetch(url: <backend-url>).then { value in
    // value
}.then {value in 
	// value
}.done {value in 
	// value
}.catch {error in
	//error
}
recover()

当然,有时候希望在发生错误前给一个默认值,可以用recover()函数


fetch(url: <imageurl>).recover { error -> Promise<UIImage> in
    return UIImage(name: <placeholder>)
}...

因此上面图片请求例子就可以写成这样

func fetch(url: URL) -> Promise<Data> {
    return Promise { seal in
        URLSession.shared.dataTask(with: url!) { data, _, error in
            seal.resolve(data, error)
        }.resume()
    }
}

fetch(url: <backendURL>).then { data in
		//解析返回结果
    return JSONParsePromise(data)
}.then { imageurl in
    //下载图片文件
    return fetch(url: imageurl)
}.then { data in
		//UI赋值
    imageView.image = UIImage(data: data)
}.catch { error in
	//错误处理	
}

其他链元素

firstly()

使用firstly()来作为一个链的开始

firstly {
    return fetch(url:url)
}.then{ 
    ...
}
ensure()

如果想在promise完成之前做的事情,可以使用ensure()

firstly {
    fetch(url: url)
}.ensure {
    cleanup()
}.catch {
    handle(error: $0)
}

比如在请求中加入网络指示器

func fetch(url: URL) -> Promise<Data> {
    return Promise { seal in
        URLSession.shared.dataTask(with: url!) { data, _, error in
            seal.resolve(data, error)
        }.resume()
    }
}

firstly {
//开始旋转
  UIApplication.shared.isNetworkActivityIndicatorVisible = true
  return fetch(url: <backendURL>)
}.then { data in
    return JSONParsePromise(data) // we skip the wrapping of JSONParsing
}.then { imageurl in
    return fetch(url: imageurl)
}.then { data in
    imageView.image = UIImage(data: data)
}.ensure {
	//在完成之前执行
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
}.catch { error in
    // in case we have an error
}
get()

如果想在同样的数据结果做不同的事情,可以用get()来讲任务分开

firstly {
    fetch(url: url)
}.get { data in
    //…
}.done { data in
    // 跟get数据相同,并没有发生变化
}
when()

使用when来链接多个promise,当每个promise都完成时才会回调,如果其中一个promise发生错误,那么就会跳到catch

firstly {
    when(fulfilled: promise1(), promise2())
}.done { result1, result2 in
    //…
}

自定义回调线程

Promise默认的所有回调都在主线程,如果想在其他线程中处理事,可以这样做

fetch(url: url).then(on: .global(QoS: .userInitiated)) {
    //then closure executes on different thread 
}

延迟Delay

let waitAtLeast = after(seconds: 0.3)

firstly {
    fetch(url: url)
}.then {
    waitAtLeast
}.done {
    //…
}

超时

使用race()来处理超时

let timeout = after(seconds: 4)

race(when(fulfilled: fetch(url:url)).asVoid(), timeout).then {
    //…
}

重试

网络请求不会总是成功,有时我们希望在一次失败时,再重新请求几次,那么可以使用recover().

func attempt<T>(maximumRetryCount: Int = 3, delayBeforeRetry: DispatchTimeInterval = .seconds(2), _ body: @escaping () -> Promise<T>) -> Promise<T> {
    var attempts = 0
    func attempt() -> Promise<T> {
        attempts += 1
        return body().recover { error -> Promise<T> in
            guard attempts < maximumRetryCount else { throw error }
            return after(delayBeforeRetry).then(on: nil, attempt)
        }
    }
    return attempt()
}

attempt(maximumRetryCount: 3) {
    fetch(url: url)
}.then {
    //…
}.catch { _ in
    // we still failed
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值