@Lefe_x提出了一个常见的需求:
感受到这个需求的普遍性,虽然流程不复杂,但是却有着不同的实现方法,且体现出不同的优雅程度. 也许当遇到更加复杂的流程时,更优雅的实现将有效提高代码可读性和可调试性。
此Demo是这个需求的实现Demo,只是把下载音频改为下载图片, 给出了基于callback,PromiseKit,rj_async的三种实现.其中callback,PromiseKit是@Lefe_x已经提出的,我只是照着敲了一边代码:
//callback实现
- (void)onCbDownloadButton:(id)sender {
_downloadedImageView.image = nil;
//确定是否可以下载
[self cbDeterminDownloadWithCallback:^(BOOL download) {
if (!download) {
return;
}
//请求下载地址
[_cbDownloadButton setTitle:@"获取下载地址..." forState:UIControlStateNormal];
_cbDownloadButton.enabled = NO;
_pmkDownloadButton.hidden = YES;
_rjDownloadButton.hidden = YES;
[self cbQueryDownloadUrlWithCallback:^(NSString *url) {
if (url) {
//下载
[_cbDownloadButton setTitle:@"下载中..." forState:UIControlStateNormal];
[self cbDownloadImageWithUrl:url callback:^(UIImage *image) {
//下载成功
if (image) {
_downloadedImageView.image = image;
}
else {
//下载失败
[[[Alert alloc] initWithTitle:@"提示" message:@"下载失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
}
//恢复UI
[_cbDownloadButton setTitle:@"callback决定下载" forState:UIControlStateNormal];
_cbDownloadButton.enabled = YES;
_pmkDownloadButton.hidden = NO;
_rjDownloadButton.hidden = NO;
}];
}
else {
[[[Alert alloc] initWithTitle:@"提示" message:@"获取下载地址失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
//恢复UI
[_cbDownloadButton setTitle:@"callback决定下载" forState:UIControlStateNormal];
_cbDownloadButton.enabled = YES;
_pmkDownloadButton.hidden = NO;
_rjDownloadButton.hidden = NO;
}
}];
}];
}
//PromiseKit实现
- (void)onPmkDownloadButton:(id)sender {
_downloadedImageView.image = nil;
//确定是否可以下载
[self pmkDeterminDownload]
.then(^{
//可以下载,请求下载地址
[_pmkDownloadButton setTitle:@"获取下载地址..." forState:UIControlStateNormal];
_pmkDownloadButton.enabled = NO;
_cbDownloadButton.hidden = YES;
_rjDownloadButton.hidden = YES;
return [self pmkQueryDownloadUrl];
})
.then(^(NSString *url) {
//获取下载地址成功
//开始下载
[_pmkDownloadButton setTitle:@"下载中..." forState:UIControlStateNormal];
return [self pmkDownloadImageWithUrl:url];
})
.then(^(UIImage *image) {
//下载成功
_downloadedImageView.image = image;
})
.catch(^(NSError *error) {
//出错提示
if (error.code == -3) {
[[[Alert alloc] initWithTitle:@"提示" message:@"获取下载地址失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
}
else if (error.code == -4) {
[[[Alert alloc] initWithTitle:@"提示" message:@"下载失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
}
})
.ensure(^{
//恢复UI
[_pmkDownloadButton setTitle:@"PromiseKit决定下载" forState:UIControlStateNormal];
_pmkDownloadButton.enabled = YES;
_cbDownloadButton.hidden = NO;
_rjDownloadButton.hidden = NO;
});
}
rj_async实现方式基于RJIterator中的async异步块:
- (void)onRjDownloadButton:(id)sender {
_downloadedImageView.image = nil;
rj_async(^{
//决定是否可以下载
if (![rj_await([self rjDeterminDownload]).value boolValue]) {
//不可下载
return;
}
//请求下载地址
[_rjDownloadButton setTitle:@"获取下载地址..." forState:UIControlStateNormal];
_rjDownloadButton.enabled = YES;
_cbDownloadButton.hidden = YES;
_pmkDownloadButton.hidden = YES;
NSString *url = rj_await([self rjQueryDownloadUrl]).value;
if (!url) {
//获取下载地址失败
[[[Alert alloc] initWithTitle:@"提示" message:@"获取下载地址失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
return;
}
//开始下载
[_rjDownloadButton setTitle:@"下载中..." forState:UIControlStateNormal];
UIImage *image = rj_await([self rjDownloadImageWithUrl:url]).value;
if (!image) {
//下载失败
[[[Alert alloc] initWithTitle:@"提示" message:@"下载失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil] show];
return;
}
//下载成功
_downloadedImageView.image = image;
})
.finally(^{
//恢复UI
[_rjDownloadButton setTitle:@"rj_async决定下载" forState:UIControlStateNormal];
_rjDownloadButton.enabled = YES;
_cbDownloadButton.hidden = NO;
_pmkDownloadButton.hidden = NO;
});
}