iOS中使用NSProgress类来创建UI进度条的方法详解_IOS

一、引言

在iOS7之前,系统一直没有提供一个完整的框架来描述任务进度相关的功能。这使得在开发中进行耗时任务进度的监听将什么麻烦,在iOS7之后,系统提供了NSProgress类来专门报告任务进度。

二、创建单任务进度监听器

单任务进度的监听是NSProgress最简单的一种运用场景,我们来用定时器模拟一个耗时任务,示例代码如下:

@interface ViewController ()
{
 NSProgress * progress;
}
@end

@implementation ViewController

- (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
 //这个方法将创建任务进度管理对象 UnitCount是一个基于UI上的完整任务的单元数
 progress = [NSProgress progressWithTotalUnitCount:10];
 NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(task) userInfo:nil repeats:YES];
 //对任务进度对象的完成比例进行监听
 [progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{
 NSLog(@"进度= %f",progress.fractionCompleted);
}
-(void)task{
 //完成任务单元数+1

 if (progress.completedUnitCount<progress.totalUnitCount) {
  progress.completedUnitCount +=1;
 }

}

上面的示例代码中,fractionCompleted属性为0-1之间的浮点值,为任务的完成比例。NSProgress对象中还有两个字符串类型的属性,这两个属性将进度信息转化成固定的格式:

//显示完后比例 如:10% completed
@property (null_resettable, copy) NSString *localizedDescription;
//完成数量 如:1 of 10
@property (null_resettable, copy) NSString *localizedAdditionalDescription;

三、创建多任务进度监听器

上面演示了只有一个任务时的进度监听方法,实际上,在开发中,一个任务中往往又有许多子任务,NSProgress是以树状的结构进行设计的,其支持子任务的嵌套,示例如下:

- (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
 //这个方法将创建任务进度管理对象 UnitCount是一个基于UI上的完整任务的单元数
 progress = [NSProgress progressWithTotalUnitCount:10];
 //对任务进度对象的完成比例进行监听
 [progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil];
 //向下分支出一个子任务 子任务进度总数为5个单元 即当子任务完成时 父progerss对象进度走5个单元
 [progress becomeCurrentWithPendingUnitCount:5];
 [self subTaskOne];
 [progress resignCurrent];
 //向下分出第2个子任务
 [progress becomeCurrentWithPendingUnitCount:5];
 [self subTaskOne];
 [progress resignCurrent];
}

-(void)subTaskOne{
 //子任务总共有10个单元
 NSProgress * sub =[NSProgress progressWithTotalUnitCount:10];
 int i=0;
 while (i<10) {
  i++;
  sub.completedUnitCount++;
 }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{
 NSLog(@"= %@",progress.localizedAdditionalDescription);
}

NSProgress的这种树状设计模式乍看起来确实有些令人费解,有一点需要注意,becomeCurrentWithPendingUnitCount:方法的意义是将此NSProgress对象注册为当前线程任务的根进度管理对象,resignCurrent方法为取消注册,这两个方法必须成对出现,当一个NSProgress对象被注册为当前线程的根节点时,后面使用类方法 progressWithTotalUnitCount:创建的NSProgress对象都默认作为子节点添加。

四、iOS9之后进行多任务进度监听的新设计方法

        正如上面的例子所演示,注册根节点的方式可读性很差,代码结构也不太清晰,可能Apple的工程师们也觉得如此,在iOS9之后,NSProgress类中又添加了一些方法,通过这些方法可以更加清晰的表达进度指示器之间的层级结构,示例代码如下:

- (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
 //这个方法将创建任务进度管理对象 UnitCount是一个基于UI上的完整任务的单元数
 progress = [NSProgress progressWithTotalUnitCount:10];
 //对任务进度对象的完成比例进行监听
 [progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil];
 //创建子节点
 NSProgress * sub = [NSProgress progressWithTotalUnitCount:10 parent:progress pendingUnitCount:5];
 NSProgress * sub2 = [NSProgress progressWithTotalUnitCount:10 parent:progress pendingUnitCount:5];
 for (int i=0; i<10; i++) {
  sub.completedUnitCount ++;
  sub2.completedUnitCount ++;
 }
}

如上面代码所示,代码结构变得更加清晰,可操作性也更强了。

五、一点小总结

//获取当前线程的进度管理对象根节点
//注意:当有NSProgress对象调用了becomeCurrentWithPendingUnitCount:方法后,这个方法才能获取到
+ (nullable NSProgress *)currentProgress;
//创建一个NSProgress对象,需要传入进度的单元数量
+ (NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount;
//和上一个方法功能相似 iOS9之后的新方法
+ (NSProgress *)discreteProgressWithTotalUnitCount:(int64_t)unitCount;
//iOS9之后的新方法 创建某个进度指示器节点的子节点
+ (NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount parent:(NSProgress *)parent pendingUnitCount:(int64_t)portionOfParentTotalUnitCount;
//NSProgress实例的初始化方法 自父节点参数可以为nil
- (instancetype)initWithParent:(nullable NSProgress *)parentProgressOrNil userInfo:(nullable NSDictionary *)userInfoOrNil;
//注册为当前线程根节点
- (void)becomeCurrentWithPendingUnitCount:(int64_t)unitCount;
//取消注册 与注册方法必须同步出现
- (void)resignCurrent;
//iOS9新方法 向一个节点中添加一个子节点
- (void)addChild:(NSProgress *)child withPendingUnitCount:(int64_t)inUnitCount;
//进度单元总数
@property int64_t totalUnitCount;
//已完成的进度单元数
@property int64_t completedUnitCount;
//是否可取消
@property (getter=isCancellable) BOOL cancellable;
//是否可暂停
@property (getter=isPausable) BOOL pausable;
//进度比例 0-1之间
@property (readonly) double fractionCompleted;
//取消
- (void)cancel;
//暂停
- (void)pause;
//恢复
- (void)resume

六、关于NSProgress对象的用户配置字典

在NSProgress对象的用户字典中可以设置一些特定的键值来进行显示模式的设置,示例如下:

//设置剩余时间 会影响localizedAdditionalDescription的值
/*
例如:0 of 10 — About 10 seconds remaining
*/
[progress setUserInfoObject:@10 forKey:NSProgressEstimatedTimeRemainingKey];
//设置完成速度信息 会影响localizedAdditionalDescription的值
/*
例如:Zero KB of 10 bytes (15 bytes/sec)
*/
[progress setUserInfoObject:@15 forKey:NSProgressThroughputKey];
/*
下面这些键值的生效 必须将NSProgress对象的kind属性设置为 NSProgressKindFile
NSProgressFileOperationKindKey键对应的是提示文字类型 会影响localizedDescription的值
NSProgressFileOperationKindKey可选的对应值如下:
NSProgressFileOperationKindDownloading: 显示Downloading files…
NSProgressFileOperationKindDecompressingAfterDownloading: 显示Decompressing files…
NSProgressFileOperationKindReceiving: 显示Receiving files…
NSProgressFileOperationKindCopying: 显示Copying files…
*/
 [progress setUserInfoObject:NSProgressFileOperationKindDownloading forKey:NSProgressFileOperationKindKey];
/*
NSProgressFileTotalCountKey键设置显示的文件总数
例如:Copying 100 files…
*/
 [progress setUserInfoObject:@100 forKey:NSProgressFileTotalCountKey];
//设置已完成的数量
[progress setUserInfoObject:@1 forKey:NSProgressFileCompletedCountKey];

七、在UI中显示进度步骤总结
以下有几个在视图或者视图控制器中显示进度的步骤:
1.在你调用一个长时间运行的任务之前,借助+progressWithTotalUnitCount:.方法建立一个NSProgress实例。 参数totalUnitCount将会包括“要完成的总工作单元的数量”。
 
有一点很重要,要从UI图层的角度完全理解这个数值;你不会被要求猜测有多少个实际工作对象以及有多少种类的工作单元(字节?像素?文字行数?)。如果你遍历集合并且计划为每一个集合元素调用该实例对象,该参数经常会是1或者也许是一个集合中的元素的数量 。
 
2.使用KVO注册一个进度的fractionCompleted属性的观察者。类似于NSOperation,NSProgress被设计借助KVO来使用。在MAC,这使得通过Cocoa Bindings绑定一个NSProgress实例到一个进度条或者标签上变得非常容易。在iOS上,你将会在KVO observer handle中手动更新你的UI。
 
除了fractionCompleted, completedUnitCount和totalUnitCount属性之外,NSProgress也有一个localizedDescription (@"50% completed"),并且还有一个localized Additional Description (@"3 of 6"),其能够被绑定到文本标签。KVO通知在改变NSProgress对象属性值的线程中发送,因此确保在你的主线程中手动更新UI。
 
3.当前的进度对象通过调用-becomeCurrentWithPendingUnitCount:方法建立新的进度对象。在这里,pendingUnitCount这个参数相当于“是要被接收者完成的总的工作单元的量要完成的工作的一部分”。你可以多次调用这个方法并且每次传递totalUnitCount(本次代码完成的占比)的一部分。在集合元素的迭代示例中,我们将会在每一次迭代中调用[progress becomeCurrentWithPendingUnitCount:1];
 
4.调用工作对象的方法。由于当前进度是一个局部线程概念,你必须在你调用becomeCurrentWithPendingUnitCount:的相同的线程中做这个事情。如果工作对象的API被设计成在主线程中调用,那这就不是一个问题,就像我对大部分API的看法那样(Brent Simmons 也这么认为)。
 
但是如果你的UI 层正在建立一个后台队列并且调用工作对象来同步那个队列,那要确保将 becomeCurrentWithPendingUnitCount:和resignCurrent放到相同的dispatch_async()块中调用。
 
5.在你的进度对象中调用-resignCurrent。这个方法是和-becomeCurrentWith PendingUnitCount:相对应的,并且会调用相同的次数 。你可以在实际工作被完成以前调用resignCurrent,因此你不需要等待,直到你得到一个来自工作对象的完成通知。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索ios
, ui
, 进度条
NSProgress
android进度条详解、jquery ui 进度条、步骤流程进度条ui界面、android 圆形进度条ui、jquery ui 进度条例子,以便于您获取更多的相关知识。

时间: 2025-01-21 04:51:14

iOS中使用NSProgress类来创建UI进度条的方法详解_IOS的相关文章

C++中可以接受任意多个参数的函数定义方法(详解)_C 语言

能够接受任意多个参数的函数,可以利用重载来实现.这种函数的执行过程类似于递归调用,所以必须要有递归终止条件. #include <iostream> #include <bitset> void print() {} // 递归终止条件.这是必需的. template<typename Type, typename... Types> void print(const Type& arg, const Types&... args) { std::cou

iOS Webview自适应实际内容高度的4种方法详解_IOS

//第一种方法 - (void)webViewDidFinishLoad:(UIWebView *)webView { CGFloat webViewHeight=[webView.scrollView contentSize].height; CGRect newFrame = webView.frame; newFrame.size.height = webViewHeight; webView.frame = newFrame; _webTablewView.contentSize = C

iOS应用中使用Toolbar工具栏方式切换视图的方法详解_IOS

关于UIToolbarToolBar工具栏是视图View的属性,可以在工具栏上添加工具栏按钮Bar Button Item(可以是自定义的Custom.也可以是系统自带的BarButtonSystemItem ),视图控制器可以通过工具栏项对视图中内容进行操作. 注意事项: 在导航栏控制器中会有一个UIToolBar实例,但默认是隐藏的,如果需要显示,需要通过这个方法将其打开: 在这里需要注意的是,与UINavigationBar类似,导航控制器拥有且只拥有一个UIToolBar实例,但UITo

Android更新UI的四种方法详解_Android

前言 相信每位Android开发者们都知道更新UI只能在主线程中进行,若是在子线程执行任务后需要更新UI,则需要借助handler跳转到主线程中.以下介绍几种操作UI的方法. 一.使用Handler的handleMessage() Handler的构造 public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { fina

iOS延迟执行方法详解_IOS

近日学习了延迟执行的几种方法,分享一下. 1.performSelector(NSObject)方法  2.NSTimer方法  3.GCD方法  4.sleep(NSThread)方法 延迟执行代码: - (void)delayDo : (id)sender { NSLog(@"do:%@",sender); } 1.performSelector(NSObject)方法 这是iOS中常用的一种延迟执行方法. 特点:这个方法必须要在主线程中使用.可以传递参数.可以取消操作,不能暂停.

java中四种生成和解析XML文档的方法详解(介绍+优缺点比较+示例)_java

众所周知,现在解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J 下面首先给出这四种方法的jar包下载地址 DOM:在现在的Java JDK里都自带了,在xml-apis.jar包里 SAX:http://sourceforge.net/projects/sax/ JDOM:http://jdom.org/downloads/index.html DOM4J:http://sourceforge.net/projects/dom4j/  一.介绍及优缺点分析

Javascript定义类(class)的三种方法详解_javascript技巧

将近20年前,Javascript诞生的时候,只是一种简单的网页脚本语言.如果你忘了填写用户名,它就跳出一个警告. 如今,它变得几乎无所不能,从前端到后端,有着各种匪夷所思的用途.程序员用它完成越来越庞大的项目. Javascript代码的复杂度也直线上升.单个网页包含10000行Javascript代码,早就司空见惯.2010年,一个工程师透露,Gmail的代码长度是443000行! 编写和维护如此复杂的代码,必须使用模块化策略.目前,业界的主流做法是采用"面向对象编程".因此,Ja

JS中Json数据的处理和解析JSON数据的方法详解_javascript技巧

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C.C++.C#.Java.JavaScript.Perl.Python等).这些特性使JSON成为理想的数据交换语言. 易于人阅读和编写,同时也易于机器解析和生成(一般用于提升网络传输速率). JSON的规则很简单: 对象是一个无序的"'名称/值'对"集合.一个对象以&quo

iOS中 最新微信支付/最全的微信支付教程详解

版权声明:本文为博主原创文章,未经博主允许不得转载. 每日更新关注:http://weibo.com/hanjunqiang  新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些参数. 2. 下载微信支付sdk 3. 客户端请求订单,后台与微信后台交互,返回给客户端支付参数 4. 调用微信客户端,由微信客户端和微信服务器打交道: 5. 客户端和服务端都会收到支付结果:(前台消息不可靠,