CocoaPods trunk is moving to be read-only. Read more on the blog, there are 18 months to go.

EasyDownloadSession 2.0.3

EasyDownloadSession 2.0.3

TestsTested
LangLanguage SwiftSwift
License MIT
ReleasedLast Release Jun 2016
SPMSupports SPM

Maintained by Javier Laguna.



  • By
  • Javier Laguna

Readme Score

EasyDownloadSession allows pausing and resuming downloads, giving the developer full control of the tasks execution.

Usage

EasyDownload Session is built on top of NSURLSession, contains a wrap around the session object that will take care of scheduling new download tasks for you.

It can be configured to run as many concurrent operations as needed but the default behaviour is 1 running task. It should be noted that this pod will help also for uploading but for conveniency we will refer to all transfers as downloads.

IMPORTANT: maximum number of downloads per host is 100.

Cache has been disabled.

There are two ways of adding new downloads:

  • scheduleDownloadWithId: It will add the task to a stack and will run whenever there is a free download slot.

  • forceDownloadWithId: it will start the task immediately, pausing other download if necessary.

We can find a good example of the usage of this code in [email protected]:lagubull/SocialChallenge.git

Where we are using EasyDownload Session to add requests for downloading large images that will be afterwards processed and displayed in a tableview, therefore we use the stack provided by this pod as we are more interested in newer requests than we are in old ones.

Stacks

EasyDownloadSession can manage as many stacks as you may need, before scheduling any download you should create a stack and register it in the session.

        let mediaStack = Stack()

        DownloadSession.sharedInstance.registerStack(stack: mediaStack,
                                                     stackIdentifier:kJSCMediaDownloadStack)

Schedule

We add the requests to the stack respecting the current download task.

After a download has finished successfully, A success block will be triggered. If the download finishes failure block will be triggered. Additionally, the progress block will be called to notify the progress of the task.

class func retrieveMediaForPost(post: JSCPost, retrievalRequired: ((postId: String) -> Void)?, success: ((result: AnyObject?, postId: String) -> Void)?, failure: ((error: NSError?, postId: String) -> Void)?) {

        let mySuccess = success
        let myFailure = failure

        if post.userAvatarRemoteURL != nil {

            let operation = JSCLocalImageAssetRetrievalOperation.init(postId: post.postId!)

            operation.onCompletion = { JSCOperationOnCompletionCallback in

                if let imageMedia = JSCOperationOnCompletionCallback {

                    mySuccess?(result: imageMedia,
                               postId: post.postId!)
                }
                else {

                    retrievalRequired?(postId: post.postId!)

                    DownloadSession.scheduleDownloadWithId(post.postId!,
                                                           fromURL: NSURL.init(string: post.userAvatarRemoteURL!)!,
                                                           stackIdentifier: kJSCMediaDownloadStack,
                                                           progress: nil,
                                                           success: { (taskInfo: DownloadTaskInfo!, responseData: NSData?) -> Void in

                                                            let storeOperation = JSCMediaStorageOperation.init(postId: post.postId!, data: responseData)

                                                            storeOperation.onSuccess = { JSCOperationOnSuccessCallback in

                                                                if let imageMedia = JSCOperationOnSuccessCallback {

                                                                    mySuccess?(result: imageMedia, postId: post.postId!)
                                                                }
                                                                else {

                                                                    myFailure?(error: nil, postId: post.postId!)
                                                                }
                                                            }

                                                            storeOperation.onFailure = { JSCOperationOnFailureCallback in

                                                                myFailure?(error: nil, postId: post.postId!)
                                                            }

                                                            storeOperation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

                                                            JSCOperationCoordinator.sharedInstance.addOperation(storeOperation)
                        },
                                                           failure: { (taskInfo, error) -> Void in

                                                            myFailure?(error: error, postId: post.postId!)
                    })
                }
            }

            operation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

            JSCOperationCoordinator.sharedInstance.addOperation(operation)
        }
        else {

            myFailure?(error: nil,
                       postId: post.postId!)
        }
    }
#pragma mark - Retrieval

+ (void)retrieveMediaForPost:(JSCPost *)post
           retrievalRequired:(void (^)(NSString *postId))retrievalRequired
                     success:(void (^)(id result, NSString *postId))success
                     failure:(void (^)(NSError *error, NSString *postId))failure;
{
 [EDSDownloadSession scheduleDownloadWithId:post.postId
                                    fromURL:[NSURL URLWithString:post.userAvatarRemoteURL]
                                    progress:nil
                                     success:^(EDSDownloadTaskInfo *downloadTask,
                                               NSData *responseData)
                 {
                     JSCMediaStorageOperation *storeOPeration =
                      [[JSCMediaStorageOperation alloc] initWithPostID:post.postId
                                                                  data:responseData];

                     storeOPeration.onSuccess = ^(id result)
                     {
                         if (result)
                         {
                             if (success)
                             {
                                 success(result, post.postId);
                             }
                         }
                         else
                         {
                             if (failure)
                             {
                                 failure(nil, post.postId);
                             }
                         }
                     };

                     storeOPeration.onFailure = ^(NSError *error)
                     {
                         if (failure)
                         {
                             failure(error, post.postId);
                         }
                     };

                     storeOPeration.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier;

                     [[JSCOperationCoordinator sharedInstance] addOperation:storeOPeration];
                 }
                                                   failure:^(EDSDownloadTaskInfo *downloadTask, NSError *error)
                 {
                     if (failure)
                     {
                         failure(error, post.postId);
                     }
                 }];
}

An alternative signature for a single completion block is available

  DownloadSession.scheduleDownloadWithId(post.postId!,
                                                           fromURL: NSURL.init(string: post.userAvatarRemoteURL!)!,
                                                           stackIdentifier: kJSCMediaDownloadStack,
                                                           progress: nil,
                                                           completion: { (taskInfo: DownloadTaskInfo!, responseData: NSData?, error: NSError?) -> Void in

                                                            if error == nil {

                                                                let storeOperation = JSCMediaStorageOperation.init(postId: post.postId!, data: responseData)

                                                                storeOperation.onSuccess = { JSCOperationOnSuccessCallback in

                                                                    if let imageMedia = JSCOperationOnSuccessCallback {

                                                                        mySuccess?(result: imageMedia, postId: post.postId!)
                                                                    }
                                                                    else {

                                                                        myFailure?(error: nil, postId: post.postId!)
                                                                    }
                                                                }

                                                                storeOperation.onFailure = { JSCOperationOnFailureCallback in

                                                                    myFailure?(error: nil, postId: post.postId!)
                                                                }

                                                                storeOperation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

                                                                JSCOperationCoordinator.sharedInstance.addOperation(storeOperation)
                                                            }
                                                            else {

                                                                myFailure?(error: error, postId: post.postId!)
                                                            }
                    })
                }
            }

Force Download

This will effectively pause all downloads start this one and then start any other download that can up to maxDownloads.

After a download has finished successfully, A success block will be triggered. If the download finishes failure block will be triggered.

Additionally, the progress block will be called to notify the progress of the task.

class func retrieveMediaForPost(post: JSCPost, retrievalRequired: ((postId: String) -> Void)?, success: ((result: AnyObject?, postId: String) -> Void)?, failure: ((error: NSError?, postId: String) -> Void)?) {

        let mySuccess = success
        let myFailure = failure

        if post.userAvatarRemoteURL != nil {

            let operation = JSCLocalImageAssetRetrievalOperation.init(postId: post.postId!)

            operation.onCompletion = { JSCOperationOnCompletionCallback in

                if let imageMedia = JSCOperationOnCompletionCallback {

                    mySuccess?(result: imageMedia,
                               postId: post.postId!)
                }
                else {

                    retrievalRequired?(postId: post.postId!)

                    DownloadSession.forceDownloadWithId(post.postId!,
                                                        fromURL: NSURL.init(string: post.userAvatarRemoteURL!)!,
                                                        stackIdentifier: kJSCMediaDownloadStack,
                                                        progress: nil,
                                                        success: { (taskInfo: DownloadTaskInfo!, responseData: NSData?) -> Void in

                                                            let storeOperation = JSCMediaStorageOperation.init(postId: post.postId!, data: responseData)

                                                            storeOperation.onSuccess = { JSCOperationOnSuccessCallback in

                                                                if let imageMedia = JSCOperationOnSuccessCallback {

                                                                    mySuccess?(result: imageMedia, postId: post.postId!)
                                                                }
                                                                else {

                                                                    myFailure?(error: nil, postId: post.postId!)
                                                                }
                                                            }

                                                            storeOperation.onFailure = { JSCOperationOnFailureCallback in

                                                                myFailure?(error: nil, postId: post.postId!)
                                                            }

                                                            storeOperation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

                                                            JSCOperationCoordinator.sharedInstance.addOperation(storeOperation)
                        },
                                                        failure: { (taskInfo, error) -> Void in

                                                            myFailure?(error: error, postId: post.postId!)
                    })
                }
            }

            operation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

            JSCOperationCoordinator.sharedInstance.addOperation(operation)
        }
        else {

            myFailure?(error: nil,
                       postId: post.postId!)
        }
    }
#pragma mark - Retrieval

+ (void)retrieveMediaForPost:(JSCPost *)post
           retrievalRequired:(void (^)(NSString *postId))retrievalRequired
                     success:(void (^)(id result, NSString *postId))success
                     failure:(void (^)(NSError *error, NSString *postId))failure;
{
[EDSDownloadSession forceDownloadWithId:post.postId
                                fromURL:[NSURL URLWithString:post.userAvatarRemoteURL]
                               progress:nil
                                success:^(EDSDownloadTaskInfo *downloadTask,
                                               NSData *responseData)
                 {
                     JSCMediaStorageOperation *storeOPeration =
                      [[JSCMediaStorageOperation alloc] initWithPostID:post.postId
                                                                  data:responseData];

                     storeOPeration.onSuccess = ^(id result)
                     {
                         if (result)
                         {
                             if (success)
                             {
                                 success(result, post.postId);
                             }
                         }
                         else
                         {
                             if (failure)
                             {
                                 failure(nil, post.postId);
                             }
                         }
                     };

                     storeOPeration.onFailure = ^(NSError *error)
                     {
                         if (failure)
                         {
                             failure(error, post.postId);
                         }
                     };

                     storeOPeration.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier;

                     [[JSCOperationCoordinator sharedInstance] addOperation:storeOPeration];
                 }
                                                   failure:^(EDSDownloadTaskInfo *downloadTask, NSError *error)
                 {
                     if (failure)
                     {
                         failure(error, post.postId);
                     }
                 }];
}

An alternative signature for a single completion block is available

DownloadSession.forceDownloadWithId(post.postId!,
                                                        fromURL: NSURL.init(string: post.userAvatarRemoteURL!)!,
                                                        stackIdentifier: kJSCMediaDownloadStack,
                                                        progress: nil,
                                                        completion: { (taskInfo: DownloadTaskInfo!, responseData: NSData?, error: NSError?) -> Void in

                                                            if error == nil {

                                                                let storeOperation = JSCMediaStorageOperation.init(postId: post.postId!, data: responseData)

                                                                storeOperation.onSuccess = { JSCOperationOnSuccessCallback in

                                                                    if let imageMedia = JSCOperationOnSuccessCallback {

                                                                        mySuccess?(result: imageMedia, postId: post.postId!)
                                                                    }
                                                                    else {

                                                                        myFailure?(error: nil, postId: post.postId!)
                                                                    }
                                                                }

                                                                storeOperation.onFailure = { JSCOperationOnFailureCallback in

                                                                    myFailure?(error: nil, postId: post.postId!)
                                                                }

                                                                storeOperation.targetSchedulerIdentifier = kJSCLocalDataOperationSchedulerTypeIdentifier

                                                                JSCOperationCoordinator.sharedInstance.addOperation(storeOperation)
                                                            }
                                                            else {

                                                                myFailure?(error: error, postId: post.postId!)
                                                            }
                    })
                }
            }

Concurrent Downloads

You can use the property maxDownloads to increase the number of concurrent downloads.

    mediaStack.maxDownloads = 4
    [EDSDownloadSession downloadSession].maxDownloads = @(4);

Pause

Pausing a download stops the task and stores the progress in memory so that it can be resumed later on.

All stacks may be paused at any time:

    DownloadSession.pauseDownloads()

Specific stacks may be stopped just as easily:

    DownloadSession.pauseDownloadsInStack(kJSCMediaDownloadStack)

Resume

After a download has been manually paused, it can be resumed and it will continue from whenever it had been stopped.

To restart all downloads (within the stablished limits) you may call:

    DownloadSession.resumeDownloads()

To resume an specific stack, however:

    DownloadSession.resumeDownloadsInStack(kJSCMediaDownloadStack)

Cancel

All tasks may be cancelled at any time:

    DownloadSession.cancelDownloads()

Specific tasks may be stopped just as well:

     DownloadSession.cancelDownload(post.postId!,
                                    stackIdentifier: kJSCMediaDownloadStack)

Found an issue?

Please open a new Issue here if you run into a problem specific to EasyAlert, have a feature request, or want to share a comment.

Pull requests are encouraged and greatly appreciated! Please try to maintain consistency with the existing coding style. If you’re considering taking on significant changes or additions to the project, please communicate in advance by opening a new Issue. This allows everyone to get onboard with upcoming changes, ensures that changes align with the project’s design philosophy, and avoids duplicated work.

Thank you!