source https://github.com/jdg/MBProgressHUD
MBProgressHUD is an iOS drop-in class that displays a translucent HUD with an indicator and/or labels while work is being done in a background thread. The HUD is meant as a replacement for the undocumented, private UIKit UIProgressHUD with some additional features.
MBProgressHUD是一个iOS中继承的子类,当在后台线程中执行一些任务时,将展示出一个半透明的指示器或者标签.毫无疑问,HUD是用来替换苹果自身使用的私有API的,但同时该HUD会提供更多地特性.
以下是本人使用该开源库的心得分享以及简单地使用教程
1. 将MBProgressHUD.h MBProgressHUD.m 拖入到工程项目当中,MBProgressHUD本身支持ARC与非ARC
看其源码,其控制ARC与非ARC的宏值得学习
#if __has_feature(objc_instancetype)
#define MB_INSTANCETYPE instancetype
#else
#define MB_INSTANCETYPE id
#endif
#if __has_feature(objc_arc)
#define MB_STRONG strong
#else
#define MB_STRONG retain
#endif
#if __has_feature(objc_arc_weak)
#define MB_WEAK weak
#elif __has_feature(objc_arc)
#define MB_WEAK unsafe_unretained
#else
#define MB_WEAK assign
#endif
#if __has_feature(objc_arc)
#define MB_AUTORELEASE(exp) exp
#define MB_RELEASE(exp) exp
#define MB_RETAIN(exp) exp
#else
#define MB_AUTORELEASE(exp) [exp autorelease]
#define MB_RELEASE(exp) [exp release]
#define MB_RETAIN(exp) [exp retain]
#endif
2. 初始化以及简单地使用心得
我用同步网络请求来模拟阻塞操作,请将以下两个文件添加进工程项目中
YXSTHTTPRequest.h
#import <UIKit/UIKit.h>
@interface YXSTHTTPRequest : NSObject
/**
同步网络请求
这是用来进行同步网络请求的,该网络请求忽略本地缓存,使用此同步网络请求需要配合线程使用,否则会阻塞主线程
@param url 网络地址字符串
@param timeOut 超时的时间(当把请求设置成POST时,请求时间会被设置成240秒的默认值,自己设置的低于240秒的无效)
@param setRequest 一个用于配置 NSMutableURLRequest 的 block
@param result 当同步请求有效时,接收数据,或者出错时接收error block
@return none
*/
+ (void)syncConnectionWithURL:(NSString *)url timeOut:(NSTimeInterval)time
setRequest:(void (^)(NSMutableURLRequest *request))setRequest
result:(void (^)(NSData *data, NSError *error))result;
@end
YXSTHTTPRequest.m
#import "YXSTHTTPRequest.h"
@implementation RootViewController
+ (void)syncConnectionWithURL:(NSString *)url timeOut:(NSTimeInterval)time
setRequest:(void (^)(NSMutableURLRequest *request))setRequest
result:(void (^)(NSData *data, NSError *error))result
{
//创建一个网络请求
//NSURLRequestReloadIgnoringLocalCacheData(忽略本地缓存)
NSMutableURLRequest *request = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:time];
//配置request
setRequest(request);
//开始同步链接
//The downloaded data for the URL request. Returns nil if a connection could not be created or if the download fails.
NSError *connectionError = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:&connectionError];
result(data, connectionError);
}
@end
几个关于线程的宏定义
// 系统子线程池(并发执行)
#define SYS_CONCURRENT_QUEUE_H dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
#define SYS_CONCURRENT_QUEUE_D dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define SYS_CONCURRENT_QUEUE_L dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
#define SYS_CONCURRENT_QUEUE_B dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
// 系统主线程池(序列执行)
#define SYS_SERIAL_QUEUE dispatch_get_main_queue()
#define SYS_UI_QUEUE dispatch_get_main_queue()
初始化以及使用的步骤
// 初始化 MBProgressHUD 对象
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithWindow:self.view.window];
// 添加进当前视图中
[self.view addSubview:hud];
// 显示动画
[hud showAnimated:YES
whileExecutingBlock:^{
// 阻塞的代码
// 请在此处添加需要等待操作的代码
}
onQueue:SYS_SERIAL_QUEUE
completionBlock:^{
// 结束后从父视图中移除
[hud removeFromSuperview];
[hud release];
}];
查看其源码(如下所示),其 whileExecutingBlock 执行在queue中,也就是说需要自己给queue设定参数,要么是序列化queue,要么是并发queue,注意
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion {
self.taskInProgress = YES;
self.completionBlock = completion;
dispatch_async(queue, ^(void) {
block();
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self cleanUp];
});
});
[self show:animated];
}
一般情况下,我们需要使用序列queue(dispatch_get_main_queue()),以下是一个完整地使用示例(请将代码放入一个button事件中)
// 初始化 MBProgressHUD 对象
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithWindow:self.view.window];
// 添加进当前视图中
[self.view addSubview:hud];
// 显示动画
[hud showAnimated:YES
whileExecutingBlock:^{
// 阻塞操作
NSString *urlStr = @"http://wallpapers.wallbase.cc/rozne/wallpaper-2903212.jpg";
[YXSTHTTPRequest syncConnectionWithURL:urlStr
timeOut:20
setRequest:^(NSMutableURLRequest *request) {
}
result:^(NSData *data, NSError *error) {
if (error == nil) {
NSLog(@"完成");
}
}];
}
onQueue:SYS_SERIAL_QUEUE
completionBlock:^{
// 结束后从父视图中移除
[hud removeFromSuperview];
[hud release];
}];
显示下载进度条(无法使用block的方式,需要设置代理)
// 初始化 MBProgressHUD 对象
hud = [[MBProgressHUD alloc] initWithWindow:self.view.window];
// 添加进父视图
[self.view addSubview:hud];
// 下载进度模式
hud.mode = MBProgressHUDModeDeterminate;
// 标签
hud.labelText = @"正在下载";
// 协议
hud.delegate = self;
// 执行
[hud showWhileExecuting:@selector(myProgress)
onTarget:self
withObject:nil
animated:YES];
- (void)myProgress
{
// 进度条显示
float progress = 0.0f;
while (progress < 1.0f) {
progress += 0.01f;
hud.progress = progress;
usleep(50000);
}
}
- (void)hudWasHidden:(MBProgressHUD *)hud
{
// Remove HUD from screen when the HUD was hidded
[hud removeFromSuperview];
[hud release];
hud = nil;
}
以下3个枚举值反应了3中下载进度的图形显示,均属于下载进度模式
MBProgressHUDModeDeterminate
MBProgressHUDModeDeterminateHorizontalBar
MBProgressHUDModeAnnularDeterminate
接下来是比较复杂的混合模式,混合了几个阶段,非常实用
@interface RootViewController ()<MBProgressHUDDelegate>
{
MBProgressHUD *HUD;
}
@end
- (void)buttonsEvent:(UIButton *)button
{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = @"连接网络...";
HUD.minSize = CGSizeMake(135.f, 135.f);
[HUD showWhileExecuting:@selector(myMixedTask)
onTarget:self
withObject:nil
animated:YES];
}
- (void)myMixedTask
{
// 阻塞操作(请将阻塞操作代替sleep函数)
sleep(2);
// 切换到下载模式(请将阻塞操作代替usleep函数)
HUD.mode = MBProgressHUDModeDeterminate;
HUD.labelText = @"下载进度";
float progress = 0.0f;
while (progress < 1.0f)
{
progress += 0.01f;
HUD.progress = progress;
usleep(50000);
}
// 切换到默认显示的模式(请将阻塞操作代替sleep函数)
HUD.mode = MBProgressHUDModeIndeterminate;
HUD.labelText = @"清理完毕";
sleep(2);
// 切换到自定义图片的模式,在主线程中显示图片(说明此方法执行在子线程中)
__block UIImageView *imageView;
dispatch_sync(SYS_UI_QUEUE, ^{
UIImage *image = [UIImage imageNamed:@"37x-Checkmark.png"];
imageView = [[UIImageView alloc] initWithImage:image];
});
HUD.customView = [imageView autorelease];
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = @"完成";
// 延时2秒后消失
sleep(2);
}
- (void)hudWasHidden:(MBProgressHUD *)hud
{
// Remove HUD from screen when the HUD was hidded
[hud removeFromSuperview];
[hud release];
hud = nil;
}
总结:
1. 涉及到下载进度的时候,必须使用代理来实现进度条的显示
2. 这是用来指示阻塞操作的指示器
3. 混合模式使用非常方便
4. 可以使用自定义View