(0045) iOS 开发之MBProgressHUD 源码学习
第一部分:学习所得和分析线程
1. 学习到了kvo 的使用 和屏幕方向的旋转判断。
2. 如果调起这个 HUD 的方法不是在主线程调用的,是不是会 crash 呢,你是怎么处理的?会,
#define MBMainThreadAssert() NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread.");
处理:回到主线程加载,两种方法
1.[self performSelectorOnMainThread:@selector(onmainTestHub) withObject:self waitUntilDone:NO];
2.
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self onmainTestHub];
});
除了-show:方法以外,MBProgressHUD还为我们提供了一组显示方法,可以让我们在显示HUD的同时,执行一些后台任务,我们在此主要介绍两个。其中一个是-showWhileExecuting:onTarget:withObject:animated:,它是基于target-action方式的调用,在执行一个后台任务时显示HUD,等后台任务执行完成后再隐藏HUD,具体实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated { methodForExecution = method; targetForExecution = MB_RETAIN(target); objectForExecution = MB_RETAIN(object); // Launch execution in new thread self.taskInProgress = YES; // 耗时操作 [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil]; // Show HUD view [self show:animated]; }
- (void)launchExecution { @autoreleasepool { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" // Start executing the requested task [targetForExecution performSelector:methodForExecution withObject:objectForExecution]; #pragma clang diagnostic pop // Task completed, update view in main thread (note: view operations should // be done only in the main thread) [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO]; } } |
可以看到,-showWhileExecuting:onTarget:withObject:animated:首先将taskInProgress属性设置为YES,这样在调用-show:方法时,即使设置了graceTime,也确保能在任务完成之前显示HUD。然后开启一个新线程,来异步执行我们的后台任务,最后去显示HUD。
而在异步调用方法-launchExecution中,线程首先是维护了自己的一个@autoreleasepool,所以在我们自己的方法中,就不需要再去维护一个@autoreleasepool了。之后是去执行我们的任务,在任务完成之后,再回去主线程去执行清理操作,并隐藏HUD窗口。
另一个显示方法是-showAnimated:whileExecutingBlock:onQueue:completionBlock:,它是基于GCD的调用,当block中的任务在指定的队列中执行时,显示HUD窗口,任务完成之后执行completionBlock操作,最后隐藏HUD窗口。我们来看看它的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 | - (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]; } |
这个方法也是首先将taskInProgress属性设置为YES,然后开启一个线程去执行block任务,最后主线程去执行清理操作,并隐藏HUD窗口。
第二部分:使用demo 写的很详细。
http://www.cnblogs.com/huangjianwu/p/4638542.html#undefined