Development of iOS The Idea of Large File Download and Breakpoint Download
- 2021-10-11 19:46:33
- OfStack
Large file download
Scenario 1: Use NSURLConnection and its proxy method, and NSFileHandle (not recommended after iOS9)
Related variables:
@property (nonatomic,strong) NSFileHandle *writeHandle;
@property (nonatomic,assign) long long totalLength;
1
>
Send a request
// Create 1 Request
NSURL *url = [NSURL URLWithString:@""];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Use NSURLConnection Initiate 1 Asynchronous requests
[NSURLConnection connectionWithRequest:request delegate:self];
2
>
Processing the data returned by the server in the proxy method
/** The following proxy method is called when a response is received from the server
1. Create 1 Empty files
2. Use 1 Handle objects are associated with this empty file to facilitate writing data after the empty file
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response
{
// Create a file path
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
NSString *filePath = [caches stringByAppendingPathComponent:@"videos.zip"];
// Create 1 Empty files to sandbox
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:filePath contents:nil attributes:nil];
// Create 1 File handles used to write data
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
// Get the total size of the file
self.totalLength = response.expectedContentLength;
}
/** The following proxy method is called when the file data returned by the server is received
Append data to the back of a file using a handle object
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data
{
// Move to the back of the file
[self.writeHandle seekToEndOfFile];
// Write data to the sandbox
[self.writeHandle writeData:data];
}
/**
Close the handle object when all data is received
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Close the file and empty it
[self.writeHandle closeFile];
self.writeHandle = nil;
}
Scenario 2: NSURLSessionDownloadTask and NSFileManager using NSURLSession
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@""];
// It can be used to download large files, and the data will be stored in the sandbox tmp Folder
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// location : The path where temporary files are stored (downloaded files)
// Create a storage file path
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
// response.suggestedFilename The recommended file name, 1 Like the file name on the server side 1 To
NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];
/** Cut or copy temporary files to Caches Folder
AtPath : File path before cutting
toPath : Cut file path
*/
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr moveItemAtPath:location.path toPath:file error:nil];
}];
[task resume];
Scenario 3: Proxy method using NSURLSessionDownloadDelegate and NSFileManger
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// Create 1 Download tasks and set up agents
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@""];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url];
[task resume];
}
#pragma mark -
/**
Called after downloading
Parameters: lication Path to temporary file (downloaded file)
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
// Create a storage file path
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
// response.suggestedFilename The recommended file name, 1 Like the file name on the server side 1 To
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
/** Cut or copy temporary files to Caches Folder
AtPath : File path before cutting
toPath : Cut file path
*/
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
/**
Whenever the download is finished, 1 Part of the time (it may be called multiple times)
Parameters:
bytesWritten How much was downloaded for this call
totalBytesWritten How many lengths have you accumulated into the sandbox
totalBytesExpectedToWrite Total file size
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
// You can do some operations such as displaying progress here
}
/**
Use when resuming downloads
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
// Used for breakpoint transmission
}
Breakpoint download
Option 1:
1
>
Add two variables and buttons on the basis of scenario 1
@property (nonatomic,assign) long long currentLength;
@property (nonatomic,strong) NSURLConnection *conn;
2
>
Add the following code to the proxy method that receives the data returned by the server
// Record breakpoints and accumulate file length
self.currentLength += data.length;
3
>
Click the button to start (continue) or pause the download
- (IBAction)download:(UIButton *)sender {
sender.selected = !sender.isSelected;
if (sender.selected) { // Continue (start) downloading
NSURL *url = [NSURL URLWithString:@""];
// **** The key point is to use NSMutableURLRequest, Set the request header Range
NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:url];
NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
[mRequest setValue:range forHTTPHeaderField:@"Range"];
// Download
self.conn = [NSURLConnection connectionWithRequest:mRequest delegate:self];
}else{
[self.conn cancel];
self.conn = nil;
}
}
4
>
Add the following code to line 1 of the proxy method that receives server response execution to prevent duplicate creation of empty files
if (self.currentLength) return;
Scenario 2: Proxy method using NSURLSessionDownloadDelegate
Required variables
@property (nonatomic,strong) NSURLSession *session;
@property (nonatomic,strong) NSData *resumeData; // Contains the starting location for continuing the download and the download url
@property (nonatomic,strong) NSURLSessionDownloadTask *task;
Method
// Create 1 Request
NSURL *url = [NSURL URLWithString:@""];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Use NSURLConnection Initiate 1 Asynchronous requests
[NSURLConnection connectionWithRequest:request delegate:self];
0