There are couple of challenges I am facing with streaming request using AFNetworking 2.0.
I want to upload lot of files (~50MB) to server and the request HAVE TO BE STREAMING. (otherwise app will crash due to memory pressure)
I have tried various ways to do it in AFNetworking 2.0 without any success. This is what I am doing currently:
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:baseServiceUrl parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
int imageIndex = 0;
for (NSURL *tempFileUrl in tempFilesUrlList) {
NSString* fileName = [NSString stringWithFormat:@"image%d", imageIndex];
NSError *appendError = nil;
[formData appendPartWithFileURL:tempFileUrl name:fileName error:&appendError];
imageIndex++;
}
} error:&error];
AFHTTPRequestOperation *requestOperation = nil;
requestOperation = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
DLog(@"Uploading files completed: %@\n %@", operation, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(@"Error: %@", error);
}];
[requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
double percentDone = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
DLog(@"progress updated(percentDone) : %f", percentDone);
}];
[requestOperation start];
This works fine, but its not streaming. It prepares the request in memory can crashes if request is too big. I had experimented with native sockets and streams, but Apple says they may disapprove the app because of it.
Another approach I have tried is following:
AFHTTPSessionManager* manager = [AFHTTPSessionManager manager];
NSString *appID = [[NSBundle mainBundle] bundleIdentifier];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:appID];
NSURL* serviceUrl = [NSURL URLWithString:baseServiceUrl];
manager = [manager initWithBaseURL:serviceUrl sessionConfiguration:configuration];
NSURLSessionDataTask *uploadFilesTask = [manager POST:baseServiceUrl parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
int imageIndex = 0;
for (NSURL *tempFileUrl in tempFilesUrlList) {
NSString* fileName = [NSString stringWithFormat:@"image%d", imageIndex];
NSError *appendError = nil;
[formData appendPartWithFileURL:tempFileUrl name:fileName error:&appendError];
imageIndex++;
}
} success:^(NSURLSessionDataTask *task, id responseObject) {
DLog(@"Files uploaded successfully: %@\n %@", task, responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
DLog(@"Error: %@", error);
}];
[progressBar setProgressWithUploadProgressOfTask:uploadFilesTask animated:true];
But this gives me run time error saying:
Terminating app due to uncaught exception 'NSGenericException', reason: 'Upload tasks in background sessions must be from a file' *** First throw call stack: ( 0 CoreFoundation 0x02cc75e4 __exceptionPreprocess + 180 1 libobjc.A.dylib
0x02a4a8b6 objc_exception_throw + 44 2 CFNetwork
0x0459eb6c -[__NSCFBackgroundSessionBridge uploadTaskForRequest:uploadFile:bodyData:completion:] + 994 3
CFNetwork 0x045f2f37 -[__NSCFURLSession uploadTaskWithStreamedRequest:] + 73
(Must be streaming, and able to continue in background)