A modern download manager based on NSURLSession to deal with asynchronous downloading, management and persistence of multiple files.

Overview

TWRDownloadManager

TWRDownloadManager

A modern download manager for iOS (Objective C) based on NSURLSession to deal with asynchronous downloading, management and persistence of multiple files.

TWRDownloadManager is a singleton instance and can thus be called in your code safely from wherever you need to. The idea of writing yet another download manager library stemmed from the fact that at the time of the writing (and yet still) there were no available open source projects based on the new NSURLSession APIs made available by Apple in iOS 7.

TWRDownloadManager leverages the power of NSURLSession and NSURLSessionDownloadTask to make downloading of files and keeping track of their progress a breeze.


09.22.2014 - UPDATE!!!

v1.0.0 of TWRDownloadManager now supports background modes. The API has changed so it’s not backwards compatible, hence its bump to v1.0.0. See the documentation below for further information.

A demo project has also been added to showcase the use of the download manager in its simplest form.

v1.1.0 of TWRDownloadManager adds the ability to pass a block when creating the download to keep track of an estimated remaining download time. The algorithm can definitely be improved but it works.

Updated demo project.

Installing the library

To use the library, just add the dependency to your Podfile:

platform :ios
pod 'TWRDownloadManager'

Run pod install to install the dependencies.

Next, import the header file wherever you want to use the manager:

#import <TWRDownloadManager/TWRDownloadManager.h>

Since TWRDownloadManager is a singleton you could import it in the .pch file of your project so that it can be accessed and used wherever you need it without worrying about importing it in each of your classes.

Usage

TWRDownloadManager provides facilities for the following task:

  • downloading files;
  • persisting downloaded files and saving them to disk;
  • keeping track of download progress via block syntax;
  • being notified of the download completion via block syntax;
  • deleting downloaded files;
  • checking for file existence.

All the following instance methods can be called directly on [TWRDownloadManager sharedManager].

Downloading files

- (void)downloadFileForURL:(NSString *)url
                  withName:(NSString *)fileName
          inDirectoryNamed:(NSString *)directory
             progressBlock:(void(^)(CGFloat progress))progressBlock
           completionBlock:(void(^)(BOOL completed))completionBlock
      enableBackgroundMode:(BOOL)backgroundMode;

- (void)downloadFileForURL:(NSString *)url
          inDirectoryNamed:(NSString *)directory
             progressBlock:(void(^)(CGFloat progress))progressBlock
           completionBlock:(void(^)(BOOL completed))completionBlock
      enableBackgroundMode:(BOOL)backgroundMode;

- (void)downloadFileForURL:(NSString *)url
             progressBlock:(void(^)(CGFloat progress))progressBlock
           completionBlock:(void(^)(BOOL completed))completionBlock
      enableBackgroundMode:(BOOL)backgroundMode;

The easiest way to get started is by simply passing to the last of the aforementioned methods the URL string of the file that needs to be downloaded. You will get a chance to pass in two blocks that will help you keep track of the download progress (a float from 0 to 1) and of the completion of the task.

All the files, once downloaded will be moved from the /tmp directory of the device to the Caches directory. This is done for two reasons:

  • the /tmp directory can be cleaned once in a while to make sure that any partial, cancelled or failed downloads get properly disposed of and do not occupy space both on the device and in iTunes backups;
  • the Caches directory is not synced by default with the user's iCloud documents. This is in compliance with Apple's rules about content that – not being user-specific – can be re-downloaded from the internet and should not be synced with iCloud.

If a directory name is provided, a new sub-directory will be created in the Cached directory.

Once the file is finished downloading, if a name was provided by the user, it will be used to store the file in its final destination. If no name was provided the manager will use by default the last path component of the URL string (e.g. for http://www.example.com/files/my_file.zip, the final file name would be my_file.zip).

Checking for current downloads

To check if a file is being downloaded, you can use one of the following methods:

- (BOOL)isFileDownloadingForUrl:(NSString *)url withProgressBlock:(void(^)(CGFloat progress))block;
- (BOOL)isFileDownloadingForUrl:(NSString *)url withProgressBlock:(void(^)(CGFloat progress))block completionBlock:(void(^)(BOOL completed))completionBlock;

As with the previous download methods, you get a chance to be called back for progress and completion.

To retrieve a list of current files being downloaded, you can use the following:

- (NSArray *)currentDownloads;

This method returns an array of NSString objects with the URLs of the current downloads being performed.

Canceling downloads

The downloads, which are uniquely referenced by the download manager by the provided URL, can either be canceled singularly or all together with a single call via one of the two following methods:

- (void)cancelAllDownloads;
- (void)cancelDownloadForUrl:(NSString *)urlString;

File management

TWRDownloadManager also provides some facilities to deal with downloaded files.

You can check for existence...

- (BOOL)fileExistsForUrl:(NSString *)urlString;
- (BOOL)fileExistsForUrl:(NSString *)urlString inDirectory:(NSString *)directoryName;
- (BOOL)fileExistsWithName:(NSString *)fileName;
- (BOOL)fileExistsWithName:(NSString *)fileName inDirectory:(NSString *)directoryName;

...and retrieve the file location with the following ones:

- (NSString *)localPathForFile:(NSString *)fileIdentifier;
- (NSString *)localPathForFile:(NSString *)fileIdentifier inDirectory:(NSString *)directoryName;

Deleting files

Downloaded files can be deleted via the following methods:

- (BOOL)deleteFileForUrl:(NSString *)urlString;
- (BOOL)deleteFileForUrl:(NSString *)urlString inDirectory:(NSString *)directoryName;
- (BOOL)deleteFileWithName:(NSString *)fileName;
- (BOOL)deleteFileWithName:(NSString *)fileName inDirectory:(NSString *)directoryName;

Background Mode

To enable background downloads in iOS 7+, you should conform to the following steps:

  • enable background modes in your project. Select the project in the Project Navigator in Xcode, select your target, then select the Capabilities tab and finally enable Background Modes:

Enable Background modes

  • add the following method to your AppDelegate
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    [TWRDownloadManager sharedManager].backgroundTransferCompletionHandler = completionHandler;   
}
  • register for local notifications in your application:didFinishLaunchingWithOptions: so that you can display a message to the user when the download completes:
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
}

Using TWRDownloadManager with custom UITableViewCell

TWRDownloadManager, being able to keep track of multiple downloads at once, could be used to show a list of current downloads inside a table view.

These are just a couple of suggestions on how it could be achieved by using TWRDownloadManager.

In your UITableViewCell subclass, import <TWRDownloadManager/TWRDownloadObject.h>.

Define your progress and completion blocks as two properties:

@property (strong, nonatomic) TWRDownloadProgressBlock progressBlock;
@property (strong, nonatomic) TWRDownloadCompletionBlock completionBlock;

In your implementation (.m) file, define their block getters:

- (TWRDownloadProgressBlock)progressBlock {
    __weak typeof(self)weakSelf = self;
    return ^void(CGFloat progress){
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
						// do something with the progress on the cell!
        });
    };
}

- (TWRDownloadCompletionBlock)completionBlock {
    __weak typeof(self)weakSelf = self;
    return ^void(BOOL completed){
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
						// do something 
        });
    };
}

Finally, don't forget to nil out the blocks before the cell can be reused:

-(void)prepareForReuse {
    self.progressBlock = nil;
}

Now in your code, whenever you set up a new cell you can get the cell's own progress and completion block and pass them to the download manager. Voilà!

Requirements

TWRDownloadManager requires iOS 7.x or greater.

License

Usage is provided under the MIT License. See LICENSE for the full details.

Contributions

All contributions are welcome. Please fork the project to add functionalities and open a pull request to have them merged into the master branch in the next releases.

Comments
  • uitableviewcell  example

    uitableviewcell example

    could you please add an uitableviewcell exmaple to the project, im using the uitableviewcell but when i press back and then i return i got sigbart exception, please help

    opened by syrakozz 3
  • remaining time

    remaining time

    can you please add :

    Pause and resume a download Set maximum number of concurrent downloads Custom download path and auto path creation Download speed and remaining time Download cancellation If a download has been stopped and the local file has not been deleted, when you will restart the download to the same local path, the download will start where it has stopped using the HTTP Range header (14.35).

    opened by syrakozz 3
  • Download is freeze when bad network

    Download is freeze when bad network

    Hi, I test my app switch between good network. -> bad network -> good network. first, all files downloading, then I change to bad network. all files in current download is freeze (it's right). But when I change back to good network. Some files download good, but some files still freeze. I thought these files stop download, I just check them "isFileDownloadingForUrl" or not then "downloadFileForURL" again. But I check them still downloading and in array current download. If want these download finish. I have to stop and redownload all. That not good with user. Please help

    opened by veila 2
  • iOS 7 NSURLSessionConfiguration

    iOS 7 NSURLSessionConfiguration

    iOS 7 does not support backgroundSessionConfigurationWithIdentifier, and causes a crash when the sharedManager inits.

    Temporary workaround:

    NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"re.touchwa.downloadmanager"];
    
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {
    backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"re.touchwa.downloadmanager"];
    }
    
    self.backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil];
    
    opened by spestian 2
  • Received memory warning when downloading large file (100mb)

    Received memory warning when downloading large file (100mb)

    I get like 3 warnings and than it crashes. Is there a way to get around this? Seems like it's downloading to memory first? I've seen some post about downloading directly to disk.

    Any ideas?

    opened by mjsibbald 1
  • Checking downloading

    Checking downloading

    Please fix two methods or add new one

    • (BOOL)isFileDownloadingForUrl:(NSString *)fileIdentifier withProgressBlock:(void(^)(CGFloat progress))block;
    • (BOOL)isFileDownloadingForUrl:(NSString *)fileIdentifier withProgressBlock:(void(^)(CGFloat progress))block completionBlock:(void(^)(BOOL completed))completionBlock;

    They replace download's blocks if arguments are NULL - it's bad behaviour. Or please add new method

    • (BOOL)isFileDownloadingForUrl:(NSString *)fileIdentifier { BOOL retValue = NO; TWRDownloadObject *download = [self.downloads objectForKey:fileIdentifier]; if (download) { retValue = YES; } return retValue; }
    opened by SoundBlaster 0
  • Progress block nil

    Progress block nil

    I have had issues using a progress block on a uitableviewcell as you show. It seems that even though you are checking for a nil progressblock, once it is called on the main thread there is a possibility it has been nilled out since you checked.

    Here is my fix:

    - (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
     totalBytesWritten:(int64_t)totalBytesWritten
    totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    NSString *fileIdentifier = downloadTask.originalRequest.URL.absoluteString;
    TWRDownloadObject *download = [self.downloads objectForKey:fileIdentifier];
    if (download.progressBlock) {
        CGFloat progress = (CGFloat)totalBytesWritten / (CGFloat)totalBytesExpectedToWrite;
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            if(download.progressBlock){
                download.progressBlock(progress); //exception when progressblock is nil
            }
        });
    }
    
    CGFloat remainingTime = [self remainingTimeForDownload:download bytesTransferred:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
    if (download.remainingTimeBlock) {
        dispatch_async(dispatch_get_main_queue(), ^(void) {
            download.remainingTimeBlock((NSUInteger)remainingTime);
        });
    }
    }
    
    opened by burniejm 0
  • download in directory

    download in directory

    Hi

    could you please help me with this issue, I'm using twrdownloadmanager on one of my projects and i want to download my files in user document directory with a new given folder name somthing like /Documents/Music/file.mp3 but the problem is when I'm using when I'm giving directory name in anyway in even creating directory manually "TWRDownloadManager.shared()?.downloadFile(forURL: url, inDirectoryNamed: "Music". but i get the error which say can't find the directory. I'm suing swift and iOS 11.

    thanks for help <3

    opened by mjabbari 0
  • Please fix hot crash

    Please fix hot crash

    Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSURL URLByAppendingPathComponent:]: component, components, or pathExtension cannot be nil.'

    This crash I can not find it's case. It seems crash often. Please I very need use this repo

    opened by veila 0
  • Added compatibility in the podspec to watchOS, macOS and tvOS

    Added compatibility in the podspec to watchOS, macOS and tvOS

    The library is basically the same across the platforms.

    I edited the podspec to add the support to the other platforms and made some small changes to don't show the local notifications on platform different than iOS

    opened by Dzamir 1
Owner
Michelangelo Chasseur
Michelangelo Chasseur
Digger is a lightweight download framework that requires only one line of code to complete the file download task

中文说明 Digger is a lightweight download framework that requires only one line of code to complete the file download task. Based on URLSession, pure Swif

Ant 543 Oct 29, 2022
NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. ⚙️🚀

SONetworking NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. Project Folder and File Struc

Ahmad AlSofi 4 Jan 28, 2022
Thin wrapper around NSURLSession in swift. Simplifies HTTP requests.

SwiftHTTP SwiftHTTP is a thin wrapper around NSURLSession in Swift to simplify HTTP requests. Features Convenient Closure APIs Simple Queue Support Pa

Dalton 1.9k Dec 7, 2022
Easy HTTP Networking in Swift a NSURLSession wrapper with image caching support

Networking was born out of the necessity of having a simple networking library that doesn't have crazy programming abstractions or uses the latest rea

Nes 1.3k Dec 17, 2022
Lightweight lib around NSURLSession to ease HTTP calls

AeroGear iOS HTTP Thin layer to take care of your http requests working with NSURLSession. Project Info License: Apache License, Version 2.0 Build: Co

AeroGear 44 Sep 27, 2022
A progressive download manager for Alamofire

ALDownloadManager A progressive download manager for Alamofire (Alamofire下载器) The default support breakpoint continues. Sequential Download(顺序下载 ) Dow

null 48 May 1, 2022
A tiny library makes uploading and downloading easier

Features uploading/downloading multiple files concurrently or sequentially grouping tasks with awesome custom operators (||| and -->) supports backgro

Le Van Nghia 450 Nov 19, 2022
File downloading library for Swift 3

VeloxDownloader About: VeloxDownloader is an easy to use,elegant, native yet powerfull download library made with Swift 3. It abstracts all the comple

Nitin Sharma 20 Apr 24, 2019
Deal with query items, HTTP headers, request body and more in an easy, declarative way

Reusable system for complex URL requests with Swift. Deal with query items, HTTP headers, request body and more in an easy, declarative way. Check out our engineering blog to learn more!

Parable Health 19 Sep 5, 2022
Snap Scraper enables users to download media uploaded to Snapchat's Snap Map using a set of latitude and longitude coordinates.

Snap Scraper Description Snap Scraper is an open source intelligence tool which enables users to download media uploaded to Snapchat's Snap Map using

Dr Richard Matthews 58 Dec 12, 2022
ServiceData is an HTTP networking library written in Swift which can download different types of data.

ServiceData Package Description : ServiceData is an HTTP networking library written in Swift which can download different types of data. Features List

Mubarak Alseif 0 Nov 11, 2021
Native ios app to download tiktoks localy made in swift with SwiftUI

sequoia Native ios app to download tiktoks localy made in swift with SwiftUI without external dependencies. features save video localy view saved vide

fleur 9 Dec 11, 2022
Asynchronous socket networking library for Mac and iOS

CocoaAsyncSocket CocoaAsyncSocket provides easy-to-use and powerful asynchronous socket libraries for macOS, iOS, and tvOS. The classes are described

Robbie Hanson 12.3k Jan 8, 2023
Simple asynchronous HTTP networking class for Swift

YYHRequest YYHRequest is a simple and lightweight class for loading asynchronous HTTP requests in Swift. Built on NSURLConnection and NSOperationQueue

yayuhh 77 May 18, 2022
Easy to use SMJobBless, along with a full Swift implementation of the Authorization Services and Service Management frameworks

Leverage SMJobBless functionality with just one function call: let message = "Example App needs your permission to do thingamajig." let icon = Bundle.

null 20 Dec 23, 2022
🌏 A zero-dependency networking solution for building modern and secure iOS, watchOS, macOS and tvOS applications.

A zero-dependency networking solution for building modern and secure iOS, watchOS, macOS and tvOS applications. ?? TermiNetwork was tested in a produc

Bill Panagiotopoulos 90 Dec 17, 2022
BP Passport is a mobile app to help patients with blood pressure management

BP Passport - Simple for Patients BP Passport is a native mobile application written in React Native - a JavaScript library that renders native, cross

Simple 4 Sep 18, 2022
APIProvider - API Provider Package for easier API management inspired by abstraction

APIProvider Using APIProvider you can easily communicate with all API endpoints

null 1 Apr 21, 2022
Modern networking support to monitor network connectivity

ConnectivityKit Adapting to changes in network connectivity can allow for suspending or resuming network activity. When entering an elevator or going

Brennan Stehling 1 Nov 7, 2022