天天看點

iOS進度訓示器——NSProgress

一、引言

在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是以樹狀的結構進行設計的,其支援子任務的嵌套,示例如下:
           
  • //向下分支出一個子任務 子任務進度總數為5個單元 即當子任務完成時 父progerss對象進度走5個單元

    [progress becomeCurrentWithPendingUnitCount:5];

    [self subTaskOne];

    [progress resignCurrent];

    //向下分出第2個子任務

-(void)subTaskOne{

//子任務總共有10個單元
NSProgress * sub =[NSProgress progressWithTotalUnitCount:10];
int i=0;
while (i<10) {
    i++;
    sub.completedUnitCount++;
}           
NSLog(@"= %@",progress.localizedAdditionalDescription);           

NSProgress的這種樹狀設計模式乍看起來确實有些令人費解,有一點需要注意,becomeCurrentWithPendingUnitCount:方法的意義是将此NSProgress對象注冊為目前線程任務的根進度管理對象,resignCurrent方法為取消注冊,這兩個方法必須成對出現,當一個NSProgress對象被注冊為目前線程的根節點時,後面使用類方法 progressWithTotalUnitCount:建立的NSProgress對象都預設作為子節點添加。

四、iOS9之後進行多任務進度監聽的新設計方法

正如上面的例子所示範,注冊根節點的方式可讀性很差,代碼結構也不太清晰,可能Apple的工程師們也覺得如此,在iOS9之後,NSProgress類中又添加了一些方法,通過這些方法可以更加清晰的表達進度訓示器之間的層級結構,示例代碼如下:
           
  • //建立子節點

    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];

繼續閱讀