Search code examples
objective-cfiledownloadafhttprequestoperation

AFHTTPRequestOperation download file even when server return error


I'm new in Objective-c, I want to send a URL request with token to server to download the file. If token is invalid, server will return HTTP 500 error.

But I got one problem was that even operation return error, the file still been created, but the file's content is the error msg. my expectation is when operation get error, the file should not be created and downloaded. sry for poor explanation...

below is my code.

- (void)attemptResourceFileWithToken:(NSString*)token
                            from:(NSString*)url
                              to:(NSString*)targetPath
               completionHandler:(void (^)(NSError*))handler {

//create an NSURL object, which is used to make an NSURLRequest.
NSString *string = [NSString stringWithFormat:@"%@&token=%@", url, token];
NSURL *requestUrl = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:requestUrl];
DLog(@"Request URL: %@", requestUrl);

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:targetPath append:NO]];
DLog(@"Target file path: %@", targetPath);

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    DLog(@"Successfully get the response from server");
    handler(nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    DLog(@"ERR: %@", [error description]);
    handler(error);
}];

[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
    DLog(@"Downloading %ld of %lld bytes", (long) totalBytesRead, totalBytesExpectedToRead);
}];

[operation start];

}

  1. setOutputStream will save the file to the target path.
  2. if operation completed successfully, handler return nil
  3. if operation failed, return error.

what I can do so that if 3 (operation fail) then step 1 setOutputSteam will cancel or don't save the file.


Solution

  • The result you are getting is expected because the outputStream is like a temporary buffer. From the official documentation:

    The output stream that is used to write data received until the request is finished.

    By default, data is accumulated into a buffer that is stored into responseData upon completion of the request, with the intermediary outputStream property set to nil. When outputStream is set, the data will not be accumulated into an internal buffer, and as a result, the responseData property of the completed request will be nil. The output stream will be scheduled in the network thread runloop upon being set.

    What you should do is treat the file generated by outputStream as temporary. In your success callback you should move it into a more permanent location (and possibly rename it). In the error callback you can simply delete it.

    Alternative is to not set outputStream at all and try to save the responseObject. I am not at my PC ATM so I can't give you any tips on that solution just yet.

    Here is a similar question to yours, note the comments in the accepted answer - link