- 源代码基于0.91版本;
- 本篇只介绍相关公有API,同时简单说明实现方式
1. 用于快速调用HUD的类方法
1.1 在指定视图上显示和移除HUD
- 在视图中显示HUD,进入等待状态
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
- 在视图上移除HUD,退出等待状态
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;
对于没有特别要求,只需要简单屏蔽用户交互时使用;二者一般成对使用。
- 移除视图中的所有HUD,退出等待状态
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated;
此方法会遍历查找视图层级中的所有HUD视图并移除。
快速显示和隐藏HUD方法,自动管理HUD的生命周期,故在实现中设置为“隐藏后直接移除视图”,如:
// 示例的显示HUD方法
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
MBProgressHUD *hud = [[self alloc] initWithView:view];
// 类方法,只是用于快速显示或隐藏,不关心视图,故消失后直接移除
hud.removeFromSuperViewOnHide = YES;
[view addSubview:hud];
[hud show:animated];
return MB_AUTORELEASE(hud);
}
1.2 获取视图中存在的HUD对象
- 获取视图中当前显示的HUD对象
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view;
这里使用了逆序遍历view的子视图的方式,快速获取最上层的HUD对象:
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view {
// 逆序迭代(符合视图层级)
NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
for (UIView *subview in subviewsEnum) {
if ([subview isKindOfClass:self]) {
return (MBProgressHUD *)subview;
}
}
return nil;
}
- 获取视图中所有存在的HUD对象
+ (NSArray *)allHUDsForView:(UIView *)view;
2 初始化HUD的实例方法
2.1 使用UIWindow对象尺寸创建HUD
- (id)initWithWindow:(UIWindow *)window;
2.2 使用UIView对象尺寸创建HUD
- (id)initWithView:(UIView *)view;
说明:
- 二者都是通过调用initWithFrame方法进行实例化,只是参数类型不同;
- 需要创建方自主管理HUD的生存周期。
注意:
- 以上初始化方法中的参数只是由于指定HUD视图自身尺寸,并非添加到视图上。
- 添加到的父视图需要手动指定。
3 显示、隐藏HUD的相关实例方法
3.1 显示HUD视图,进入等待状态
- (void)show:(BOOL)animated;
3.2 隐藏HUD视图,退出等待状态
- (void)hide:(BOOL)animated;
3.3 在指定时间后,隐藏HUD视图,退出等待状态
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay;
以上方法,都是在通过自己实例化HUD对象后(默认为隐藏状态),自主控制HUD视图的显示与隐藏。
4 在指定任务执行时,自动显示和隐藏HUD的相关方法
4.1 使用“target - selector”方式执行后台任务
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
此方法的实现步骤:
- 在后台自动创建新线程,在其中执行预定任务;
- 同时在主线程创建并显示HUD;
- 任务完成后,在主线程中清理缓存数据,同时移除HUD,结束等待状态。
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
// 保存需要执行的参数对象
methodForExecution = method;
targetForExecution = MB_RETAIN(target);
objectForExecution = MB_RETAIN(object);
// 这里由于是开辟新线程执行任务,故是异步执行
self.taskInProgress = YES;
[NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
// 同时显示HUD视图,进入等待状态
[self show:animated];
}
- (void)launchExecution {
@autoreleasepool {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// 1.这里由于没有使用返回值,故需要向编译器添加“忽略内存泄漏”要求
// 2.此方法在支持完毕前,不会返回(卡住当前执行线程)
[targetForExecution performSelector:methodForExecution withObject:objectForExecution];
#pragma clang diagnostic pop
// 执行完毕后,执行主线程的任务
[self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
}
}
- (void)cleanUp {
// 标识任务已结束
taskInProgress = NO;
#if !__has_feature(objc_arc)
[targetForExecution release];
[objectForExecution release];
#else
// 清除保留的执行对象
targetForExecution = nil;
objectForExecution = nil;
#endif
// 隐藏HUD视图,退出等待状态
[self hide:useAnimation];
}
4.2 使用“block”方式执行后台任务
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block;
4.3 使用“block”方式执行后台任务,并在完成后执行指定任务
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion;
4.4 使用“block”方式执行后台任务,任务在指定的GCD队列中执行
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue;
4.5 使用“block”方式执行后台任务,任务在指定的GCD队列中执行,并在完成后执行指定任务
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion;
以上通过block方式执行任务的API,都是通过GCD的方式,在并发队列中执行异步任务,简化了实现。如1.4.5的方法实现:
/** 真正的block版本的异步执行函数 */
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion {
// 标识任务已开始执行
self.taskInProgress = YES;
// 将block保存到堆内存(由于completion为外部回调,不会捕获当前对象中的变量,防止是栈内存的block被释放,故需要拷贝到堆上)
self.completionBlock = completion;
// 在队列中异步执行任务
dispatch_async(queue, ^(void) {
block();
// 完成后,主线程进行清理工作
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self cleanUp];
});
});
// 同时,在主线程显示HUD视图,进入等待状态
[self show:animated];
}
网友评论