AFHTTPRequestOperation does the breakpoint resuming of file download


When I was working on a project by myself, I first came into contact with the breakpoint resuming function of file download. At that time, I found a lot of blogs and materials. Because of the first contact, I used a tool class packaged by others to do it. During the development process It is found that there will be some problems, because the probability of occurrence is small, so there is not much optimization. The tool class I was looking for at that time was written based on AFNetworking, encapsulated by the inherited AFHTTPRequestOperation class, provided an interface for pause and resume, and also rewritten some methods of the parent class, which was used at the time, and later found frequent clicks Pausing to continue will cause errors in the cursor of the file, and modifying some settings in some classes only reduces the chance of triggering.

Recently, I need to do a download breakpoint resume function. I just moved the previous method over. After using it, I found that the above problem still occurs. So I started to search for information on the Internet again, only to find that AFHTTPRequestOperation itself has completed the download task. , you only need to modify the logic of download/pause/continue/cancel you need on the external logic.

The following is the code for resuming the download from a breakpoint. Here, it cooperates with the sqlite database to read and write the download progress and download status. (The code is for reference only, because people are lazy and only write some annotations--, you can also refer to the content of the blog above)

-(void)controlModelWithModel:(DownloadModel *)download_model andType:(NSString *)type{
    NSString *md5 = download_model.model_md5_str;
    //download
    DownloadModel *model;
    BOOL hasModel = NO;
    DownloadListTable *table = (DownloadListTable *)[[DataBaseUtil shareInstance]getTableWithClass:[DownloadListTable class]];
    for (DownloadModel *m in self.modelArr) {
        if ([m.model_md5_str isEqualToString:md5]) {
            model = m;
            hasModel = YES;
        }
    }
    if (!hasModel) {
        // The corresponding model is not found in the list
        NSLog(@"error : not find model in arr");
        return;
    }
    model.model_download_flag = @"1";
    if (!model.model_download_percentage||[model.model_download_percentage isEqualToString:@"null"]) {
        model.model_download_percentage = @"0.00";
    }
    //Insert into database table, update if exists
    [table insertTableWithConfition:model];
    
    AppDelegate *app = [UIApplication sharedApplication].delegate;
    //Read the globally saved operation
    AFHTTPRequestOperation *operation = [app.downloadDic objectForKey:md5];
    NSString *name = [NSString stringWithFormat:@"%@.%@",model.model_md5_str,model.model_format];
    NSString *toPath = SAVE_MODEL_PATH(name);
    NSFileManager *fm = [NSFileManager defaultManager];
    unsigned long long downloadedBytes = 0;
    / / Determine whether the operation exists, create it if it does not exist
    if (!operation) {
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:model.model_url]];
        if ([fm fileExistsAtPath:toPath])//If it exists, it means there is a cache file
        {
            downloadedBytes = [self fileSizeAtPath:toPath];//Calculate the size of the cached file
            NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
            NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
            
            [mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
            request = mutableURLRequest;
            NSLog(@"==============Breakpoint download");
        }
        operation= [[AFHTTPRequestOperation alloc] initWithRequest:request];
        [operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:toPath append:YES]];
        [app.downloadDic setObject:operation forKey:md5];
    }
    
    //Set the progress operation
    
    [operation setDownloadProgressBlock: ^ (NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        float progress = ((float)totalBytesRead + downloadedBytes) / (totalBytesExpectedToRead + downloadedBytes);
        
        NSString *text = [NSString stringWithFormat:@"%.1f/%.1fM",((float)totalBytesRead + downloadedBytes)/1000/1000,(totalBytesExpectedToRead + downloadedBytes)/1000/1000.0];
        NSLog(@"================downloadPrecent:%.2f  size:%@",progress*100,text);
        
        //Save progress to database file
        if (![[DataBaseUtil shareInstance]isDataBaseInUse]) {
            model.model_download_percentage = [NSString stringWithFormat:@"%.2f",progress*100];
            [table updateTableWithConfition:model];
        }
    }];
    
    [operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
         //Calculate/match md5 string
         NSString *file_md5_str = [TRMD5 file_md5:toPath];
         BOOL isRight = NO;
         if ([file_md5_str isEqualToString:md5]) {
             isRight = YES;
         }
         //If md5 matches, save the data, modify the database to 3 and download is complete
         
         //If it does not match, delete the downloaded file, and the database deletes the data
         if (isRight) {
             //md5 matches successfully, completes the download, downloads the thumbnail and modifies the database information
             [self modelDownloadFinishedWithModel:model];
         }else{
             //md5 matching fails, delete the file
             [table deleteTableWithConfition:model];
             [fm removeItemAtPath:toPath error:nil];
         }
         NSLog(@"downloadFinished");
        
     } failure:^(AFHTTPRequestOperation *operation, NSError *error){
         //If the download fails, delete the file, data path information
         if (error.code == NSURLErrorCancelled || error.code == NSURLErrorNetworkConnectionLost) {
             //If canceled or the network connection is disconnected, it will not be processed and set to pause
             
         }else{
             [table deleteTableWithConfition:model];
             [fm removeItemAtPath:toPath error:nil];
             NSLog(@"downloadFail,errorCode:%@",error);
         }
     
     }];
    
    // start the operation
    switch ([type intValue]) {
        case 0://first download
            [operation start];
            model.model_download_flag = @"1";
            [table updateTableWithConfition:model];
            break;
        case 1://pause
            [operation cancel];
            operation = nil;
            [app.downloadDic removeObjectForKey:md5];
            model.model_download_flag = @"2";
            [table updateTableWithConfition:model];
            break;
        case 2://Continue to download
            [operation start];
            model.model_download_flag = @"1";
            [table updateTableWithConfition:model];
            break;
        case 3://download the completed model
            
            break;
            
        default:
            break;
    }
}
//get file size
-(unsigned long long)fileSizeAtPath:(NSString *)path{
    signed long long fileSize = 0;
    NSFileManager *fileManager = [NSFileManager new];
    if ([fileManager fileExistsAtPath:path]) {
        NSError *error = nil;
        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
        if (!error && fileDict) {
            fileSize = [fileDict fileSize];
        }
    }else{
        fileSize = 0;
    }
    return fileSize;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325551482&siteId=291194637