iOS developed of 1 the basic function of the downloader

  • 2020-06-19 11:45:56
  • OfStack

Today, Demo, which makes a downloader, downloads the specified files from the locally configured Apache server. This time, we download the html.mp4 file in the server root directory.
By convention, we first create an URL object and a request.
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/html.mp4"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
There are two points to note here. First, the string of url is in English. If Chinese appears in the string, we cannot directly call URLWithString: this method
[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
Method, otherwise it cannot be requested normally.
Since this is a download operation, we need to use NSURLConnection's proxy method to implement this, as long as we first create a proxy connecting the object and the object.
// Establish connection, execute immediately
[NSURLConnection connectionWithRequest:request delegate:self];
Now the problem is that there is more than one agent to choose from, < NSURLConnectionDownloadDelegate > and < NSURLConnectionDataDelegate > , the first contact, instinctively chose the first agent (because from the name, the first most similar). If you think like I do, you are wrong. After the method in the first agent is implemented, you can actually get the data, but you don't know where the data exists and it is not the path we specified. You can try 1.
Ok, after the first failure, we select the second agent and enter the header file. We see four methods:


// Get the response 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
// To get the data 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
// disconnect 
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
// An error occurred 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 

We can see exactly what each method does, and if you're interested in printing the parameters of each method, take a look.
The thing to add here is that we've added a couple of properties


///  File download stream 
@property (strong, nonatomic) NSOutputStream *fileStream;
///  Record the total file length 
@property (assign, nonatomic) long long fileLength;
///  Current file length 
@property (assign, nonatomic) long long currentFileLength; 

With respect to NSOutputStream, there is another NSFileHandle that can be compared with him, only the latter causes the file to be repeatedly appended. Therefore, we choose the former. We can infer from the class name that there should be one more NSInputStream, yes, one download stream, one up stream.

Step 1. In the method to get the response, we get the total length of the file from the response parameter, and set the current downloaded file length to 0, opening 1 download stream saved to the specified path, here we save to the desktop.


// Get the response 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
  self.fileLength = response.expectedContentLength;
  // The current file length is set to zero 
  self.currentFileLength = 0;
  self.fileStream = [[NSOutputStream alloc] initToFileAtPath:@"/Users/xxx/Desktop/html.mp4" append:YES];
  [self.fileStream open];
}

Step 2. We get the data, and if you print the data in this method, you'll find that when the file is large enough (a few M will do), this method is called multiple times, that is, multiple times to get the data. Therefore, we splice the data in this method, and at the same time, we should avoid taking up too much memory after data splicing. We add up the length of the downloaded data, calculate the percentage downloaded, and write it to the data stream. When calculating percentages, remember the conversion type, otherwise the result is 0, except the last one is 1.


// To get the data 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//  NSLog(@"did receive:%@",data);
  self.currentFileLength += data.length;
  float progressPercent = (float)self.currentFileLength / self.fileLength;
  NSLog(@"have downloaded: %f", progressPercent);
  [self.fileStream write:data.bytes maxLength:data.length];
}

The last step. There are actually two methods, one called after download and one called after download failure. One thing to note is that whether the download succeeds or fails, you need to close the file output stream.


// disconnect 
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  NSLog(@" Connect the end of the ");
  [self.fileStream close];
}

// An error occurred 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
  NSLog(@"%@",error);
  [self.fileStream close];
} 

This is just the basic implementation of the download function. The download progress bar will be added, and the download operation will be optimized with multiple threads, breakpoints, etc. Finally, the download operation will be encapsulated.


Related articles: