读源码系列----MBProgressHUD(加载等待框)

阅读本文前,请先去下载源代码(传送门)

MBProgressHUD是一个iOS的类,当等待后台进程执行时,可以显示出一个包含指示器或者标签的半透明的HUD。HUD是UIKit包中不允许开发者使用的UIProgressHUD的替代品。

使用前提

MBProgressHUD可以以ARC或者non-ARC方式运行在iOS的任何版本,它使用到下列Cocoa Touch框架

  • Foundation.framework
  • UIKit.framework
  • CoreGraphics.framework

我们从MBProgressHUD.h看起,首先MBProgressHUD继承子UIView,它具有View的特性,其头文件中,定义的枚举类型MBProgressHUDMode和MBProgressHUDAnimation,分别对应不同的加载等待框样式和消失动画类型。通过接下来的宏定义,来标志ARC和non-ARC模式及对BLOCK的支持。通过类方法+ (MBProgressHUD *)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; 或者通过对象方法alloc及initWithView可以获得MBProgressHUD对象,可以通过MBProgressHUD的delegate属性,将遵循MBProgressHUDDelegate协议的对象,设为委托,在MBProgressHUD将要隐藏时回调。

在程序遇到异步或者耗时较长的任务需要执行时,可以使用- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;方法,“锁住“主界面,并显示加载等待框。重点变在该函数内部,我们看一下:

- (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;
[NSThreaddetachNewThreadSelector:@selector(launchExecution)toTarget:selfwithObject:nil];
// Show HUD view
[selfshow:animated];
}

首先,我们将要执行的任务及目标对象传入后,MB_RETAIN实际只是宏,在之前说的那段头文件中,在non-ARC下,它将先将target和object的内存计数加1,熟悉内存管理的应该知道,接到参数后先retain,才能防止对象被提前释放。接着使用NSThread开一个线程,这是重点,现在有了新的一条线程,他将去执行我们的传进来的任务,可不让任务在主线程中调用,这样才不会阻塞主线程。新线程发消息给launchExecution。

- (void)launchExecution {
@autoreleasepool {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// Start executing the requested task
[targetForExecutionperformSelector:methodForExecutionwithObject:objectForExecution];
#pragma clang diagnostic pop
// Task completed, update view in main thread (note: view operations should
// be done only in the main thread)
[selfperformSelectorOnMainThread:@selector(cleanUp)withObject:nilwaitUntilDone:NO];
}
}

targetForExecution完成具体任务的执行,这时候该线程在一直执行我们的任务,performSelectorOnMainThread的意思是在主线程执行cleanUp,所以当我们任务在其他线程执行完,回到主线程时,执行cleanUp。

cleanUp执行一些release和赋值nil操作后,将执行- (void)hide:(BOOL)animated这个将去执行触发动画效果的方法,接着将调用- (void)done,在done中有一段这样的代码

if ([delegaterespondsToSelector:@selector(hudWasHidden:)]) {
[delegateperformSelector:@selector(hudWasHidden:)withObject:self];
}

向我们代理的对象发送hudWasHidden:消息,如果之前设置这确,便可以响应。

 在头文件中有

@property (atomic, copy) NSString *labelText;
@property (atomic, copy) NSString *detailsLabelText;

我们对这两个NSString类型的属性的赋值,会直接更新界面中的Label,这里使用到的是KVO编程,通过#pragma mark - KVO标记可以查看该部分代码,所有键值信息

- (NSArray *)observableKeypaths {
	return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", 
			@"detailsLabelText", @"detailsLabelFont", @"progress", nil];
}

注册键值

- (void)registerForKVO {
	for (NSString *keyPath in [self observableKeypaths]) {
		[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
	}
}


当键值改变时,更新UI

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
	if (![NSThread isMainThread]) {
		[self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO];
	} else {
		[self updateUIForKeypath:keyPath];
	}
}



你可能感兴趣的:(ios,ios,ios,cocoa,KVO,KVO,MBProgressHUD)