NSURLConnection and beginBackgroundTaskWithExpirationHandler - ios

I'm using NSURLConnection to download archive 500mb. And I want to download it on background thread, so I wrote:
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
self.theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// Cancel the connection
[self.theConnection cancel];
}];
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
}
So if I did it on main thread it download and unarchive and working well, but if I start download and press Home button, so it start working on background thread it download 70% - 80% and it freezed. Method - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error don't call.
How can I download large file on background thread?
Edit 1
I found that it called
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self.theConnection cancel];
}];
So connection finished, but I don't call endBackgroundTask in another methods.

Apple allows your app run in background thread about 10 minutes (when you press home button).
NSURLSession is what you are looking for: NSURLSession
"This API provides a rich set of delegate methods for supporting authentication and gives your app the ability to perform background downloads when your app is not running or, in iOS, while your app is suspended."

Related

How to download files in background mode iOS? And Network connection Lost

In My App I download the audio files from the server, And the files are downloaded fine when the app is in foreground and when I clicked home button or lock button to force the app to go to background, then after some time, the download is stopped and the error comes as the 1005 network connection lost. Whats the problem? Can Anybody explain the issue?
Code:
NSURL *url = [NSURL URLWithString:currentURL];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
receivedData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
myConnection = connection;
NSLog(#"%# Download Started", currentURL);
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[receivedData setLength:0];
expectedBytes = [response expectedContentLength];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
float progressive = (float)[receivedData length] / (float)expectedBytes;
[downloadProgressView setProgress:progressive];
NSInteger val = progressive*100;
downloadpercentageLabel.text = [NSString stringWithFormat:#"%ld%#",(long)val,#"%"];
//[UIApplication sharedApplication].idleTimerDisabled = YES;
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
Use background NSURLSession. It handles network interruptions and downloads exceeding 3 minutes. See Downloading Content in the Background section of The App Programming Guide for iOS, which describes background downloads. Also refer to WWDC 2013 video in What’s New in Foundation Networking (it's covered later in the video).

Continue webservice call after transition from foreground to background in iOS objective C

Suppose I call a webservice when the app is in foreground. Now if the user sends the app to background then how do I make sure that this webservice call keeps executing in the background.
This is the piece of code that I am using in my app.
Login* login = [[Login alloc]init];
[login initiateSignInProcess];
initiateSignInProcess has 4 web service calls. they are normal
functions. I am using AFNetworking.
If any of the services fail, I call it again with a delay in the failure block of afnetworking code like below:-
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
[self performSelector:#selector(getUserId) withObject:nil afterDelay:5];
}
Now I want to know that if the user sends the app to background, then how will the code execute? Will it call this function in bakcground till it succeeds?
Best to use Background Process for fetch. Here is great tutorial for solution [ http://code.tutsplus.com/tutorials/ios-7-sdk-working-with-background-fetch--mobile-20520
Not possible in iOS6.x or lesser unless your application is has specific requirement to run in background like locations, Voip, music etc...
However this is possible with iOS7, please consider having a look at this
http://redth.codes/ios7-recipe-background-fetching/
**For(large FIle Downloade use Asynchronous Method)**
NSURL *myUrl = [NSURL URLWithString:#"Enter URL HERE"];
NSURLRequest *myRequest = [NSURLRequest requestWithURL:myUrl cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
NSMutableData *myData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:myRequest delegate:self startImmediately:YES];
**For(Small FIle Downloade use Synchronous Method)**
NSURL *myUrl = [NSURL URLWithString:#"Enter URl HERE"];
NSData *myData = [NSData dataWithContentsOfURL:myUrl];
UIImage *img = [UIImage imageWithData:myData];
add NSURLConnection Delegate in .h File
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[myData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[myData appendData:data];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection release];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection release];
//download finished - data is available in myData.
}
This is depends on OS scheduling whether it allows continue to run the services in background or kill it.
Best to use Background Fetch. Here is nice tutorial http://code.tutsplus.com/tutorials/ios-7-sdk-working-with-background-fetch--mobile-20520
Hope this solve your issue.

Multiple File Upload using uploadTaskWithRequest fromFile in background

I am trying to upload multiple images using NSURLSession .It works fine when application is running in foreground.When application enter background,uploading process stop after uploading current task.I would like to upload all the files when application is in background. Any help would be greatly appreciated. Here is my code.
//background task configuration
-(void) uploadOneByOne:(NSString *)individualpath{
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:mutableUrlString]];
NSString *requestURL = [NSString stringWithFormat:#"http://myservice/Service.svc/UploadOrdersToDrive?orderFolder=%#",OrderFolderID];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestURL]];
[request setHTTPMethod:#"POST"];
NSURL *filePath =[NSURL fileURLWithPath:individualpath];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:kSessionIdentifier];
defaultSession= [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionUploadTask *uploadTask =
[defaultSession uploadTaskWithRequest:request
fromFile:filePath];
[uploadTask resume];
}
NSURLSession Delegate
receive first request response
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
NSString * str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Received String %#",str);
NSDictionary *jsonResponseData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//FolderID to create next image in same folder.
OrderFolderID =[jsonResponseData
objectForKey:#"OrderFolderID"];
}
create next request
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
if(error == nil)
{
//Remove DetailFist
[orderDetailarray removeObjectAtIndex:0];
if (orderDetailarray.count >0){
ChosenImages *item = [orderDetailarray objectAtIndex:0];
[self uploadOneByOne:item.path ];
}
}
//Update progress bar
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
//update progress bar
}
Probably you didn't wait enough for next task to start. Depending from different things like WiFi and battery status, user activity etc. your next task queued in background could start in few minutes.. or few hours.
Btw I don't see code related with completionHandler implementation.
Do not forgot to implement
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
in the App delegate and appropriate session delegate.

NSURLConnection , webservices not working in Background ios

i am new in ios , i want to make one app , in app i have to call a webservices in background ,
background code is working properly but when i try to call webservices not go to on "connectionDidFinishLoading" function
where i doing a mistake please Help me
Here is my code
1. this is my background function each 30 sec its call webservices
- (void)applicationDidEnterBackground:(UIApplication *)application
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)]) { //Check if our iOS version supports multitasking I.E iOS 4
if ([[UIDevice currentDevice] isMultitaskingSupported]) { //Check if device supports mulitasking
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your tasks that your application requires
while(TRUE)
{
//backgroundTimeRemaining time does not go down.
// NSLog(#"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[UIApplication sharedApplication].applicationIconBadgeNumber++;
NSLog(#"\n\nRunning in the background!\n\n");
[self CallWebservices2];
[NSThread sleepForTimeInterval:30]; //wait for 1 sec
}
[application endBackgroundTask: background_task];
background_task = UIBackgroundTaskInvalid;
});
}
}}
2.this is my call webservices, this code reach to CallWebservices2 function but no able to call connectionDidFinishLoading
-(void)CallWebservices2
{
NSString *urlString = [NSString stringWithFormat:#"http://yournurses.com/process/push.php?action=select_jobs&id=241"];
NSLog(#"String Url = %#",urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[connnection start];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Error==%#",error);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[nsUrlResponseDataNurse setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[nsUrlResponseDataNurse appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([nsUrlResponseDataNurse length]==0)
{}
else{
NSString *str = [[NSString alloc]initWithData:nsUrlResponseDataNurse encoding:NSUTF8StringEncoding];
allDataNurse = [str JSONValue];
NSLog(#"%#",allDataNurse);
}
}
here i define in delegate.h file
#property(nonatomic,retain)NSMutableData *nsUrlResponseDataNurse;
#property(nonatomic, retain) NSMutableArray *allDataNurse;
Regards,
Nishant Chandwani
NSURLConnection supports async network transactions "out of the box". You should not run NSURLConnection from the background. It is pointless and wasteful. The class is designed to handle background downloading efficiently.
You create an NSURLConnection on the main thread and start it running. It does it's work in the background, then calls your delegate methods on the main thread.
If you only need to get notified when the download/PUT is complete, you can use the NSURLConnection class method sendAsynchronousRequest:queue:completionHandler: which runs the whole request, then calls your completion handler once it's done. Generally you have that method call your completion handler on the main queue, since that code gets called once the URL request is finished.
Your code might look like this:
NSURL *url = [NSURL URLWithString: #"http://www.foo.php"];
NSURLRequest *request = [NSURLRequest requestWithURL: url];
[NSURLConnection sendAsynchronousRequest: request
queue: [NSOperationQueue mainQueue]
completionHandler: ^(NSURLResponse *response,
NSData *data,
NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
//The data for the response is in "data" Do whatever is required
}
}
];
That code will run the request in the background, and invoke the code in the completion block once it's finished. Simple and painless.
Asynchronous NSURLConnection call doesn't work in different runloop but mainRunLoop. Either use synchronous request in a different thread like :-
-(void)CallWebservices2
nsUrlResponseDataNurse = [NSURLConnection sendSynchronousRequest: returningResponse: error:]
}
, or if you badly want to make your code working, change the calls to :
[[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:NO];
[connnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

NSURLConnection Object Ignoring It's Implemented Methods

My question relates to the code in my single-threaded app that updates the devices' local database data via a NSURLConnection to a web service.
My NSURLConnection initialization is not going into any of it's implemented methods and it has me puzzled.
Inside my AppDelegate.m -> applicationDidFinishLaunching method, I am creating a NSURLConnection object:
//AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
// ... Building request URL here ...
NSString *requestURL = [NSString stringWithFormat:#"%#%#", URI,urlEncodedParamStr]
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestURL]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
responseData = [[NSMutableData data] retain];
if(connection !=nil)
[connection release];
}
Execution should now proceed to any of the following appropriate NSURLConnection methods
that I implemented in AppDelegate.m:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{[responseData setLength:0];}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {[responseData appendData:data];}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{//my implementation}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {//my implementation}
But instead, execution continues, with the line directly after the init of NSURLConnection *connection, not executing any of the NSURLConnection implemented methods. I have confirmed that the request is not nil and put breakpoints in the implemented NSURLConnection methods - They are not being called.
What's going on?
Thanks as always!
You need to call
[connection start];
before the remote call will actually be started.
And even then, the next line of code will execute. It's an asynchronous call and is executed in a background thread. The response is received later and your connection... method will be called then (which can be up to the timeout (30 seconds) time later).

Resources