使用开源库 JGDownloadAcceleration 控制下载队列,断点下载,加速下载

JGDownloadAcceleration

本人对原文进行了翻译,凑合看看,使用心得以后补上

https://github.com/JonasGessner/JGDownloadAcceleration

 

© 2013 Jonas Gessner

JGDownloadAcceleration is a Networking library for iOS targeted at downloading large files on to the device's hard disk.

JGDownloadAcceleration's main part is a concurrent NSOperation subclass (JGDownloadOperation) which handles the multipart download.

For managing and queuing multiple operations, JGDownloadAcceleration provides a NSOperationQueue subclass (JGOperationQueue) which handles the networking thread, activity indicator and application background task.

JGDownloadAcceleration 是一个网络库,用于iOS开发,用来同时下载多个大型文件到设备磁盘上的。

JGDownloadAcceleration 的核心是一个并发的 NSOperation 的子类(JGDownloadOperation),专门用来处理多个下载任务的。

为了管理以及队列操作,JGDownloadAcceleration 提供了一个 NSOperationQueue 的子类(JGOperationQueue),专门用来处理网络线程,活动指示器,以及程序后台任务。

Q. How does the download acceleration even work?

问.如何加速下载任务?

A. Download accelerators (multipart download) use multiple network connections to download a file from a server in chunks (each connection downloads one part of the entire content). This allows to bypass bandwidth limitations set by the server and download speeds can be drastically increased.

答.下载加速呢,实际上是多个网络链接请求去下载一个文件,从一个服务器上分段下载一个文件。这个是需要这个服务器支持的,如果服务器支持这种模式,就能下载加速。

More info: Wikipedia

Current Version: 1.2.1

Getting started

  1. Download JGDownloadAcceleration
  2. Add the whole "JGDownloadAcceleration Classes" folder to your Project
  3. Have a read through the Overview section
  4. #import "JGDownloadAcceleration.h"
  5. Start using JGDownloadAcceleration!

     1. 下载JGDownloadAcceleration

     2. 将整个文件夹 JGDownloadAcceleration Classes 拖入你的工程当中

     3. 看一下概述区域

     4. 引入头文件 JGDownloadAcceleration.h

     5. 开始使用JGDownloadAcceleration

 

Overview

JGDownloadAcceleration consists of 2 different classes that are available to use for networking.

JGDownloadAcceleration  包含了2个不同的类,用来处理网络下载任务。

JGDownloadOperation

A NSOperation subclass which does the download acceleration magic.

NSOperation 的子类完成了这些功能。

JGDownloadOperation is restricted to HTTP GET Requests and to writing downloaded content directly to the hard disk.

JGDownloadOperation 是被限制使用 HTTP GET 请求的,它直接将文件写入到了磁盘上。

Parameters to pass: A JGDownloadOperation instance required to have the url parameter, and the destinationPath parameter set. If not the Application will terminate with an Assertion Failure.

传递的参数:JGDownloadOperation 对象需要提供一个 url 链接,以及存储的目的地址,如果没有这个参数,程序将会终止并抛出 Assertion 异常。

All JGDownloadOperation instances should be initialized with the initWithURL:destinationPath:allowResume:or initWithRequest:destinationPath:allowResume: methods, where the URL or NSURLRequest, the local destination path and a BOOL to indicate whether the operation should resume (if possible) where it left of is passed. Any files located at the destination path will be removed when starting the download.

所有的 JGDownloadOperation 实例对象都应该用方法 initWithURL:destinationPath:allowResume:或者 initWithRequest:destinationPath:allowResume: 来初始化。传递 url 地址或者 url请求,一个本地存储的地址以及一个BOOL值来标示,这个下载是否可以暂停操作(如果可能的话),任何被指定的文件,在重新开始下载时都会被删除掉而重新创建。

Optionally, the number of connections to use to download the resource, a tag, and the retry count can be set.

当然,有几个链接来下载资源,标示符,重试的次数都可以设置。

    NSUInteger tag;
    NSUInteger maximumNumberOfConnections;
    NSUInteger retryCount;

By default the tag is 0 and the number of connections is 6. The retry count it the number of connections divided by 2.

默认情况下,标示符是0,而链接资源数是6,重试次数是2。

The readonly properties are:

只读属性如下:

    NSURLRequest *originalRequest;
    NSString *destinationPath;
    unsigned long long contentLength;
    NSError *error;

originalRequest and destinationPath are set in the initWithURL:destinationPath:allowResume: or initWithRequest:destinationPath:allowResume: methods and should not be changed once the operation has been initialized, therefore they are a readonly property. contentLength is the expected length (bytes) of the resource to download. This value will be 0 before the requestStartedBlock is called. error returns the failure error (it will be nil if no error occurred). The error will also be passed in the failure block. (See below for more info on the started and the failure blocks).

originalRequest 以及 destinationPath 在请求开始后就不能再改变了, contentLength 是文件大小的属性,表示要下载的文件有多大。在requestStartedBlock 调用之前,其值为0,出现错误时,返回error(如果没有错误,则返回nil)。当然呢,这个error也会传递到failure的block中去。

The custom init methods:

JGDownloadOperation can only be initialized using either of the two custom init methods.

initWithURL:destinationPath:allowResume:: In this init method the request made will be a simple HTTP GET request from the given URL. No more customization is possible.

initWithRequest:destinationPath:allowResume:: This init method allows you to use a custom NSURLRequest with JGDownloadOperation. The HTTP Method can only be GET (default). JGDownloadOperation also supports the Range header.

JGDownloadOperation 只能用下面的两种方法来初始化。

initWithURL:destinationPath:allowResume: 这个初始化方法中的request必须是HTTP GET请求,不能再设置其他的了。

initWithRequest:destinationPath:allowResume: 这个初始化方法允许你用JGDownloadOperation来定制一下请求,但是呢,这个request也只能是GET请求,JGDownloadOperation 支持Range头。

Delegates:

JGDownloadOperation uses blocks to communicate with a delegate.

    - (void)setCompletionBlockWithSuccess:(void (^)(JGDownloadOperation *operation))success failure:(void (^)(JGDownloadOperation *operation, NSError *error))failure;
    - (void)setOperationStartedBlock:(void (^)(NSUInteger tag, unsigned long long totalBytesExpectedToRead))block;

    - (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, unsigned long long totalBytesReadThisSession, unsigned long long totalBytesRead, unsigned long long totalBytesExpectedToRead, NSUInteger tag))block;

JGDownloadOperation 使用block来与代理交互。 

setOperationStartedBlock:

Used to be notified when the operation starts. The block passes the tag (default 0) of the operation and the expected content size of the resource. The blocks is called from the network thread.

用来指示操作开始了。这个block将传递出标示值以及下载资源的大小数据。这个block是被网络线程调用的。

 

setCompletionBlockWithSuccess:failure:

Used to be notified when the operation finishes and to be informed about the completion state (failed with an error or not?). The completion block passes a reference to the operation, the failure block passes a reference to the operation and the error. Both blocks are called from a background thread (not the network thread).

用来指示,但这个下载完成后,提示你完成的状态值(成功或者失败了?)。这个完成的block传递了一个operation,失败的block传递了一个error。这两个block都是在后台线程执行的(注意,不是网络线程)。

 

setDownloadProgressBlock:

Used to determine, calculate, and observe various details of the current download. This block is called on the (secondary) networking thread! It is called every time a connection inside the operation receives a chunk of data (which is automatically written to the disk). The current progress, current download speed, average download speed (and using that an estimation for the remaining time) can be calculated. For average and current speed a variable in needed to store the time intervals from the last call of the block (for the current speed) and from when the operation started. See the Example project for an implementation of this

用来确定、计算、以及观察当前下载任务的详细细节。这个block是在另外一个网络线程被调用的。当一个操作中的网络连接接受了一些数据时将会自动调用。当前的下载进度,当前的下载速度,平均的下载速度都被计算出了。对于平均的以及当前的速度计算,需要一个变量来保存每次调用时的时间戳,请看工程样例。

NSUInteger bytesRead indicates the size of the bytes read (NOT since the last call of the block, its pretty complicated because this block is called for each connection, passing the number of bytes the specific connection loaded since this specific connection last loaded a chunk of bytes).

unsigned long long totalBytesReadThisSession the total number of bytes read in this current session. (e.g If a download is paused at 50% and then resumed, this parameter will start from 0)

unsigned long long totalBytesWritten the total bytes read in total.

unsigned long long totalBytesExpectedToRead the expected content size of the resource.

NSUInteger tag the tag of the operation, very handy for managing multiple operations in a queue. 

Internally this class uses a bunch of helper classes. These should not be touched by anything but the JGDownloadOperation


JGDownloadOperation uses a metadata file to store the progress of each connection, to allow the operation to resume when failed or cancelled. The metadata file is stored at the destination path with the file extension jgd. The metadata file will automatically be removed when the operation finishes with success. Passing YES for "allowResume" in the custom init methods will result in a attempt to read the metadata file and resume from the last known state. If the metadata file or the partial downloaded content is not available then the download will start from the beginning. If NO is passed for "allowResume" then no metadata files will be written and the download will always start from the beginning. If reading the metadata file is not possible (if the file does not exist) the download will start from the beginning, overwriting any existing progress. 

JGDownloadOperation 使用元数据来存储每个链接的下载进度,允许一个下载链接断掉后能够断点续传或者取消掉这个下载链接。这个元数据存储在指定的文件路径中,后缀为jgd。当下载成功后,这个元数据会自动移除。给allowResume传递YES参数,将会试图读取这个元数据文件,来恢复最后一个保存的下载状态。如果,这个元数据或者下载的文件没有了,那么下载将会从头开始。如果给allowResume传递了NO参数。那么,将不会产生元数据文件,而且,每次都会从头开始下载。如果,无法读取元数据文件(或者这个文件不存在),那么,下载将会从头开始,重写存在的进度。

Cancellation:

cancel will stop the download, synchronize the metadata file to allow resuming the download later and leave the partially downloaded file on the disk. The failure completion block will be called with an NSURLErrorCancelled error.

cancelAndClearFiles will stop the download and remove the partially downloaded file as well as the metadata file from the disk. Neither the success completion block or the failure completion block will be called.

cancel 将会停止下载,并同步的写元数据文件,记录当前下载的信息,并将部分下载的文件保存在磁盘上。如果失败了,失败的block将会被调用。

cancelAndClearFiles 将会停止这个下载,并移除这个下载的文件以及元数据文件,不会调用任何的block

 

JGOperationQueue

A NSOperationQueue subclass which is targeted at enqueuing only JGDownloadOperation objects.

JGOperationQueue handles the shared network thread used by all JGDownloadOperation instances. Once all operations are finished the queue exits the networking thread. queue Optionally, JGOperationQueue handles the status bar NetworkActivityIndicator, according to the number of enqueued operations and the background task used for networking requests when the app runs in the background.

    BOOL handleNetworkActivityIndicator
    BOOL handleBackgroundTask

Note that when setting handleBackgroundTask to YES, the App's Info.plist file needs to have "Application uses Wi-Fi" set to YES.

NSOperationQueue 的子类,只能用来给JGDownloadOperation 对象进行入队操作。

JGOperationQueue 处理共享的网络线程,被所有的实例对象JGDownloadOperation使用着,一旦所有的操作都结束了,这个队列就从网络线程中退出。当然,JGOperationQueue 处理了状态栏上的网络指示器,当app在后台运行时。

注意,当把 handleBackgroundTask 设置成YES时,这个app的 Info.plist 文件需要将 Application uses Wi-Fi 设置成YES。

Example

An example usage can be found in the Sample Project.

Requirements

In order to take advantage of multipart download, the server from which you download a content needs to support the Range HTTP header. If it doesn't then JGDownloadAcceleration will simply use 1 connection to download the content conventionally.

为了体验多点下载文件,你下载文件的服务器需要支持Range HTTP头,否则,JGDownloadAcceleration 只会用一个链接来下载这个文件。

JGDownloadAcceleration is built for use with ARC and weak references. This means that iOS 5 or higher is required for using JGDownloadAcceleration

If your project doesn't use ARC: you must add the -fobjc-arc compiler flag to all JGDownloadAcceleration files in Target Settings > Build Phases > Compile Sources.

这是arc的,用于非arc项目,请添加标示 -fobjc-arc

 

 

使用教程:

@interface RootViewController ()
{
    JGOperationQueue *q;
}
@end

------------------------------------------------------------------------------------------

NS_INLINE NSURLRequest *netURLRequest(NSString *netPath)
{
    //创建简单的网络请求
    return [NSURLRequest requestWithURL:[NSURL URLWithString:netPath]];
}

------------------------------------------------------------------------------------------

NS_INLINE NSString * createFileOrFolderPathForSandbox(NSString *filePath)
{
    /*
     
     /Documents
     /Library/Caches
     /Library/Preferences
     /tmp
     
     */
    
    return [NSHomeDirectory() stringByAppendingString:filePath];
}

------------------------------------------------------------------------------------------

// 开始组织一个下载
    JGDownloadOperation *operation =
    [[JGDownloadOperation alloc]
     initWithRequest:netURLRequest(@"http://wallpapers.wallbase.cc/manga-anime/wallpaper-1160697.jpg")
     destinationPath:createFileOrFolderPathForSandbox(@"/Documents/wallpaper-1160697.jpg")
     allowResume:YES];

    // 使用tag值来标示每一个不同的下载
    /* -----
    operation.tag = .....
    ----- */
    
    // 计算时间相关
    __block CFTimeInterval started;
    
    // 下载成功后执行的block
    [operation setCompletionBlockWithSuccess:^(JGDownloadOperation *operation)
    {
        double kbLength = (double)operation.contentLength/1024.0f;
        CFTimeInterval delta = CFAbsoluteTimeGetCurrent() - started;
        
        NSLog(@"Success! Downloading %.2f MB took %.1f seconds, average Speed: %.2f kb/s",
              kbLength/1024.0f, delta, kbLength/delta);
    }
    failure:^(JGDownloadOperation *operation, NSError *error)
    {
        NSLog(@"Operation Failed: %@", error.localizedDescription);
    }];
    
    // 下载进度的block
    [operation setDownloadProgressBlock:^(NSUInteger bytesRead, unsigned long long totalBytesReadThisSession, unsigned long long totalBytesWritten, unsigned long long totalBytesExpectedToRead, NSUInteger tag) {
        CFTimeInterval delta = CFAbsoluteTimeGetCurrent()-started;
        NSLog(@"Progress: %.2f%% Average Speed: %.2f kB/s", ((double)totalBytesWritten/(double)totalBytesExpectedToRead)*100.0f, totalBytesReadThisSession/1024.0f/delta);
    }];
    
    // 开始下载的block
    [operation setOperationStartedBlock:^(NSUInteger tag, unsigned long long totalBytesExpectedToRead) {
        started = CFAbsoluteTimeGetCurrent();
        NSLog(@"Operation Started, JGDownloadAcceleration version %@", kJGDownloadAccelerationVersion);
    }];
    
    // 设置6个链接同时下载一个文件
    [operation setMaximumNumberOfConnections:6];
    
    // 设置失败时重复3次
    [operation setRetryCount:3];
    
    if (!q) {
        q = [[JGOperationQueue alloc] init];
        q.handleNetworkActivityIndicator = YES;
        q.handleBackgroundTask = YES;
    }
    
    // 开始下载队列
    [q addOperation:operation];

------------------------------------------------------------------------------------------

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值