NSProgress是一个用来向用户不断传递某个任务进度的类。NSProgress类内部拥有一个进度报告机制。这使得代码很容易获取工作的进度、设置界面上以呈现进度。为进度条和提示文本提供数据支持,
进度条和提示文本会在进度变更时适当地更新。它还允许用户取消或暂停工作。
属性:
@property int64_t totalUnitCount; 工作总单元数,每个NSProgress对象对应一个工作,每一个工作都会按照某单位切分数个单元;
@property int64_t completedUnitCount; 已完成的单元数;
@property (readonly) double fractionCompleted; 等于“已完成的单元数”除以“工作总单元数”;
@property(copy) NSString *localizedDescription; 格式化fractionCompleted,eg:90% completed
@property(copy) NSString *localizedAdditionalDescription; 格式化completedUnitCount of totalUnitCount, eg:90 of 100
基本测试代码片段:
NSProgress *progress = [NSProgress new];
progress.totalUnitCount = 100;
progress.completedUnitCount = 90;
NSLog(@"%lld", progress.totalUnitCount );
NSLog(@"%lld", progress.completedUnitCount );
NSLog(@"%f", progress.fractionCompleted );
NSLog(@"%@", progress.localizedDescription );
NSLog(@"%@", progress.localizedAdditionalDescription );
控制台输出:
2019-11-22 09:52:16.321161+0800 AFN[17365:1053773] 100
2019-11-22 09:52:16.321595+0800 AFN[17365:1053773] 90
2019-11-22 09:52:16.321707+0800 AFN[17365:1053773] 0.900000
2019-11-22 09:52:16.334441+0800 AFN[17365:1053773] 90% completed
2019-11-22 09:52:16.335337+0800 AFN[17365:1053773] 90 of 100
通过KVO监听NSProgress的fractionCompleted属性值变化的代码片段(OC版的AFNetworking也有类似使用):
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSProgress *progress;
@property (nonatomic, strong) NSTimer *timer; //用来周期修改NSProgress的completedUnitCount值
@end
@implementation ViewController
- (void)dealloc
{
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
[self.progress removeObserver:self forKeyPath:@"fractionCompleted"];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.progress = [NSProgress progressWithTotalUnitCount:100];
[self.progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:(__bridge void * _Nullable)(self.progress)];
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf.progress.completedUnitCount++;
}];
[self.timer fire];//立即fire
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == (__bridge void * _Nullable)(self.progress)) {
NSLog(@"fractionCompleted = %.2f", self.progress.fractionCompleted);
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
隐式添加子进度代码片段:
/*
- (void)becomeCurrentWithPendingUnitCount:(int64_t)unitCount;
从当前进度对象中切分出一个子进度,当子进度完成当前进度分给的unitCount时,
当前进度的总量增加unitCount;
*/
/*
- (void)resignCurrent;
与becomeCurrentWithPendingUnitCount配套使用, 在这两个方法中间需要设置至少一个子节点, 当子节点完成后, 总完成量会自动增加unitCount量,
如果不设置子节点, 那么总任务完成量直接增加unitCount。
注意: 这两个方法成对出现, 并且必须在同一个队列中调用。
*/
#import "ImplicitlyViewController.h"
//派生子进度,添加进度标记属性。
@interface ChildProgress : NSProgress
@property (nonatomic, copy) NSString *identify;
@end
@implementation ChildProgress
@end
@interface ImplicitlyViewController ()
@property (nonatomic, strong) NSProgress *progress;//总进度
@end
@implementation ImplicitlyViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.progress = [NSProgress progressWithTotalUnitCount:100];
//本示例只分出了两层的进度树,也可以对子进度再切分,从而形成更多层树
//分出50个任务量给任务一
[self.progress becomeCurrentWithPendingUnitCount:50];
[self subTask:@"任务一"];
[self.progress resignCurrent];
//分出50个任务量给任务二
[self.progress becomeCurrentWithPendingUnitCount:50];
[self subTask: @"任务二"];
[self.progress resignCurrent];
}
- (void)subTask:(NSString *)identify
{
//每个子任务的任务量分为100个单元, 每完成一个任务单元, 总任务完成量加上 50.0 / 100.0 = 0.5的任务单元
ChildProgress *subProgress = (ChildProgress *)[ChildProgress progressWithTotalUnitCount:100];
subProgress.identify = identify;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(task:) userInfo:@{@"childProgress" : subProgress} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)task:(NSTimer *)timer
{
//获取当前的子进度
NSDictionary *userInfo = timer.userInfo;
ChildProgress *childProgress = userInfo[@"childProgress"];
//当完成量达到总量时停止任务
if (childProgress.completedUnitCount >= childProgress.totalUnitCount) {
[timer invalidate];
return;
}
//子进度完成自己的一个单元
childProgress.completedUnitCount += 1;
//打印
NSLog(@"fractionCompleted --- %f, localizedDescription --- %@, localizedAdditionalDescription --- %@, identify:%@", self.progress.fractionCompleted, self.progress.localizedDescription, self.progress.localizedAdditionalDescription, childProgress.identify);
}
@end
显式添加子进度代码片段:
/*
+ (NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount parent:(NSProgress *)parent pendingUnitCount:(int64_t)portionOfParentTotalUnitCount
- (void)addChild:(NSProgress *)child withPendingUnitCount:(int64_t)inUnitCount
*/
#import "ExplicitViewController.h"
@interface ExplicitViewController ()
@property (nonatomic, strong) NSProgress *progress;
@end
@implementation ExplicitViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置总进度
self.progress = [NSProgress progressWithTotalUnitCount:100];
//显示获取两个子进度
NSProgress *child1 = [NSProgress progressWithTotalUnitCount:100 parent:self.progress pendingUnitCount:50];
NSProgress *child2 = [NSProgress progressWithTotalUnitCount:100 parent:self.progress pendingUnitCount:50];
//使用定时器触发子进度
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(task:) userInfo:@{@"child1" : child1, @"child2" : child2} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)task:(NSTimer *)timer
{
//获取子进度
NSDictionary *userInfo = timer.userInfo;
NSProgress *child1 = userInfo[@"child1"];
NSProgress *child2 = userInfo[@"child2"];
//当子进度完成量达到总量时停止任务
if (child1.completedUnitCount >= child1.totalUnitCount && child2.completedUnitCount >= child2.totalUnitCount) {
[timer invalidate];
return;
}
//子进度完成量+1
child1.completedUnitCount += 1;
NSLog(@"fractionCompleted --- %f, localizedDescription --- %@, localizedAdditionalDescription --- %@ --- child1", self.progress.fractionCompleted, self.progress.localizedDescription, self.progress.localizedAdditionalDescription);
child2.completedUnitCount += 1;
NSLog(@"fractionCompleted --- %f, localizedDescription --- %@, localizedAdditionalDescription --- %@ --- child2", self.progress.fractionCompleted, self.progress.localizedDescription, self.progress.localizedAdditionalDescription);
}
@end