-(void)application:(UIApplication )application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSLog(#"In performFetchWithCompletionHandler");
DownloadAlerts alertDownload = [[DownloadAlerts alloc]init];
[alertDownload getAlertsOnLocUpdate];
completionHandler(UIBackgroundFetchResultNewData); // We will add content here soon.
}
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if ([data length] >0 && error == nil) {
NSLog(#"Hello01");
} else if ([data length] == 0 && error == nil) {
NSLog(#"Hello02");
} else if (error != nil) {
NSLog(#"Hello03");
}
}];
I am executing the above piece of code in a function that gets called via the performFetchWithCompletionHandler in appdelegate.h.
When I launch the app via background fetch, none of the 3 if blocks get executed. How do I implement this? I need to download data via background fetch. Kindly help... NSUrlSession also doens't work..
Have you tried to send synchronous request? I think your`s performFetchWithCompletionHandler method finishes before NSURLConnection receives the response. by the way, are you sure that performFetchWithCompletionHandler is called? Maybe you need to set capability for it?
Need to call "completionHandler(UIBackgroundFetchResultNewData);" after you received the data, pass it into "getAlertsOnLocUpdate" method as a parameter, and call it after you receive the answer from server (in completionHandler of URLConnection)
Related
In my app, I try to download a batch of images from a server.
I'm getting a number of errors, one of which I can't find an explanation for. I checked Apple's URL loading system error codes, but I couldn't fine one for error code 12. I also got HTTP load failed (error code: -999) (which is NSURLErrorCancelled) and Task finished with error - code: -1001(which is NSURLErrorTimedOut).
I recently switched from using deprecated NSURLConnection to NSURLSession. With the former, I also got the 999 and 1001 errors, but I'm trying to find out what error code 12 means.
- (void)loadImage:(LeafletURL*)leafletURLInput isThumbnail:(BOOL)isThumbnailInput isBatchDownload:(BOOL)isBatchDownload isRetina:(BOOL)isRetina
{
isRetina_ = isRetina;
if (session)
{
/*is this the right call here? */
[session invalidateAndCancel];
[session release];
session = nil;
}
if (mImageData)
{
[mImageData release];
mImageData = nil;
}
self.leafletURL = leafletURLInput;
self.isThumbnail = isThumbnailInput;
NSString* location = (self.isThumbnail) ?leafletURL.thumbnailLocation :leafletURL.hiResImageLocation;
//// Check if the image needs to be downloaded from server. If it is a batch download, then override the local resources////
if ( ([location isEqualToString:kLocationServer] || (isBatchDownload && [location isEqualToString:kLocationResource])) && self.leafletURL.rawURL != nil )
{
//NSLog(#"final loadimage called server");
//// tell the delegate to get ride of the old image while waiting. ////
if([delegate respondsToSelector:#selector(leafletImageLoaderWillBeginLoadingImage:)])
{
[delegate leafletImageLoaderWillBeginLoadingImage:self];
}
mImageData = [[NSMutableData alloc] init];
/*download tasks have their data written to a local temp file. It’s the responsibility of the completion handler to move the file from its temporary location to a permanent location.*/
NSURL* url = [NSURL URLWithString:[leafletURL pathForImageOnServerUsingThumbnail:self.isThumbnail isRetina:isRetina]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
session = [NSURLSession sharedSession];
dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
// do something with the data
}];
[dataTask resume];
}
//// if not, tell the delegate that the image is already cached. ////
else
{
if([delegate respondsToSelector:#selector(leafletImageLoaderDidFinishLoadingImage:)])
{
[delegate leafletImageLoaderDidFinishLoadingImage:self];
}
}
}
I want to test a function in which an asynchronous task is called (async call to a webservice):
+(void)loadAndUpdateConnectionPool{
//Load the File from Server
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)responseCode;
if([httpResponse statusCode] != 200){
// Show Error
}else{
// Save Data
// Post Notification to View
}
}];
}
Since the function doesn't have a completion handler, how can I test this in my XCTest class?
-(void)testLoadConnectionPool {
[ConnectionPool loadAndUpdateConnectionPool];
// no completion handler, how to test?
XCTAssertNotNil([ConnectionPool savedData]);
}
Is there any best practice, like a timeout or anything? (I know I can't use dispatch_sempaphore without redesigning the loadAndUpdateConnectionPool function).
You post a notification on complete (post a notification on error too), so you could add an expectation for that notification.
- (void)testLoadConnectionPool {
// We want to wait for this notification
self.expectation = [self expectationForNotification:#"TheNotification" object:self handler:^BOOL(NSNotification * _Nonnull notification) {
// Notification was posted
XCTAssertNotNil([ConnectionPool savedData]);
}];
[ConnectionPool loadAndUpdateConnectionPool];
// Wait for the notification. Test will fail if notification isn't called in 3 seconds
[self waitForExpectationsWithTimeout:3 handler:nil];
}
I'm dealing the authenticate issue with Tumblr account using [NSURLConnection sendAsynchronousRequest:queue:completionHandler:] to send the authenticate request, but here I meet a tough problem:
Whenever I send the request at the first time, everything goes perfectly, but when the first authentication is done and then resend the request second time, there comes "NSURLErrorDomain error -1012".
The authenticate page is loaded in a webview so that the authentication should be done in my app without a browser. But it is interesting that if the process runs in a browser there comes no error, errors only happen when using webview.
It was weird that the authentication goes with the same code, but only the first authentication can be done, only if I reinstall the app can I authenticate it again, and after this the problem comes again.
I did everything I can chase to solve the issue, I clean the cache and cookie in webview, step the authentication process to see parameters, set the cachePolicy of the request but nothing helps.
I also found that on ios6 the process goes without any error. But on ios7 I get the -1012.
code -1012 tells me that the user cancelled the authentication, but the process goes automatically and I do not cancel it.
I'm wondering if the problem comes from the NSURLConnection.
- (void)authenticate:(NSString *)URLScheme WithViewController:(UIViewController *)con callback:(TMAuthenticationCallback)callback {
self.threeLeggedOAuthTokenSecret = nil;
self.hostViewController = con;
self.callback = callback;
[self emptyCookieJar];
NSString *tokenRequestURLString = [NSString stringWithFormat:#"http://www.tumblr.com/oauth/request_token?oauth_callback=%#", TMURLEncode([NSString stringWithFormat:#"%#://tumblr-authorize", URLScheme])];
NSLog(#"%#", tokenRequestURLString);
NSMutableURLRequest *request = mutableRequestWithURLString(tokenRequestURLString);
NSLog(#"%#", request);
[[self class] signRequest:request withParameters:nil consumerKey:self.OAuthConsumerKey
consumerSecret:self.OAuthConsumerSecret token:nil tokenSecret:nil];
[self openOAuthViewController];
NSURLConnectionCompletionHandler handler = ^(NSURLResponse *response, NSData *data, NSError *error) {
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
if (error) {
if (callback) {
callback(nil, nil, error);
}
return;
}
NSLog(#"%d", statusCode);
if (statusCode == 200) {
self.threeLeggedOAuthCallback = callback;
NSDictionary *responseParameters = formEncodedDataToDictionary(data);
self.threeLeggedOAuthTokenSecret = responseParameters[#"oauth_token_secret"];
NSURL *authURL = [NSURL URLWithString:
[NSString stringWithFormat:#"http://www.tumblr.com/oauth/authorize?oauth_token=%#",
responseParameters[#"oauth_token"]]];
[self initOAuthViewControllerWithURL:authURL];
} else {
if (callback) {
callback(nil, nil, errorWithStatusCode(statusCode));
}
}
};
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:handler];
}
Code above, everything goes normally before [NSURLConnection sendAsynchronousRequest:queue:completionHandler:],and after this method I got the error in completionHandler.
So I have been trying to create an app for a website and I've got the "Log in" page working except when it won't transition to the next view.
This is the code that I believe is causing the problem :
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSString *str=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(#"%#", str);
if ([str rangeOfString:#"The username or password you provided is invalid. Please try again."].location == NSNotFound) {
loginPageStatusLabel.text = #"Correct";
NSLog(#"Correct Login");
[self performSegueWithIdentifier:#"toHome" sender:self];
} else {
loginPageStatusLabel.text = #"Incorrect";
NSLog(#"Login Failed");
}
}];
* Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-2935.137/Keyboard/UIKeyboardTaskQueue.m:368
2014-05-11 00:06:51.426 LoginTests[3381:3e03] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished]' may only be called from the main thread.'waitUntilAllTasksAreFinished]' may only be called from the main thread.
That is the error being thrown whenever I try to "Log in". The Segue with work if I run it alone, so I am assuming the problem is that the app is trying to go to the next View before it's ready and its causing an error.
I'm fairly new to Obj-C so if I have not posted the adequate information or not called things by the proper names please inform me.
Thank You!
I don't know what value you supplied for queue parameter, but given that your completion block is performing UI updates that must happen on the main thread, you can use [NSOperationQueue mainQueue] (or manually dispatch this code to the main queue). This queue parameter specifies what queue the completion block should be added to, and because you're doing UI related stuff in your completion block, this must be done on the main thread.
Having corrected that, if you are still have assertion errors, you can add an exception breakpoint and that will help confirm precisely where this assertion error is taking place. Or look at your stack trace.
I'd also, in addition to using [NSOperationQueue mainQueue], would suggest doing some more robust error handling:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (!data) {
// for example, no internet connection or your web server is down
NSLog(#"request failed: %#", error);
return;
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
int statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200) {
// for example, 404 would mean that your web site said it couldn't find the URL
// anything besides 200 means that there was some fundamental web server error
NSLog(#"request resulted in statusCode of %d", statusCode);
return;
}
}
// if we got here, we know the request was sent and processed by the web server, so now
// let's see if the login was successful.
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// I'm looking for "Welcome" ... I doubt that's right (but I don't have access to
// your web server, so I'm guessing). But the idea is that you have to find whatever
// appears after successful login that is not in the response if login failed
if ([responseString rangeOfString:#"Welcome"].location != NSNotFound) {
loginPageStatusLabel.text = #"Correct";
NSLog(#"Correct Login");
[self performSegueWithIdentifier:#"toHome" sender:self];
} else {
loginPageStatusLabel.text = #"Incorrect";
NSLog(#"Login Failed");
}
}];
I am downloading a bunch of largish zip files with the following method. It can take a little while and so I'd like to display a progress bar.
I've researched how to do with with the delegate methods for NSURLConnection and it seems straightforward, however I want to achieve the same thing with "sendAsynchronousRequest". How can I get the number of bytes downloaded as it downloads as well as the total number of bytes expected so that I can display a progress bar? I understand that I cannot use the delegate methods if I kick off a download in the manner I am doing it.
// Begin the download process
- (void)beginDownload:(NSMutableArray *)requests {
// Now fire off a bunch of requests asynchrounously to download
self.outstandingRequests = [requests count];
for (NSURLRequest *request in requests) { // Get the request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// Error check
if ( error != nil ) {
// The alertview for login failed
self.appDelegate.warningView.title = #"Refresh Error!";
self.appDelegate.warningView.message = [error localizedDescription];
// Show the view
[self.appDelegate.warningView show];
// Debug
if ( DEBUG ) {
NSLog(#"A request failed - %d left!",self.outstandingRequests);
}
}
else {
// Debug
if ( DEBUG ) {
NSLog(#"A request is done - %d left!",self.outstandingRequests);
}
}
// Decrement outstanding requests
self.outstandingRequests--;
// No requests are left
if (self.outstandingRequests == 0) {
// Debug
if ( DEBUG ) {
NSLog(#"All requests are done!");
}
// Get rid of loading view
[self performSelector:#selector(dismissLoadingView) withObject:nil afterDelay:0.15];
}
}];
}
}
https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLConnectionDownloadDelegate_Protocol/NSURLConnectionDownloadDelegate/NSURLConnectionDownloadDelegate.html#//apple_ref/doc/uid/TP40010954-CH2-SW1
How to make an progress bar for an NSURLConnection when downloading a file?
http://iphonedevsdk.com/forum/iphone-sdk-development/24233-nsurlconnection-with-uiprogressbar.html
http://iphoneeasydevelopment.blogspot.com/2011/10/use-progess-bar-when-downloading-file.html
sendAsynchronousRequest won't work for your purposes as it doesn't call your callback until the request has completed. You'll need to use initRequest:withDelegate: and handle your own data accumulation.
When the header is received (possibly multiple times for redirects) your didReceiveResponse method will be called, you can pick up the expected size there:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_expectedBytes = (NSUInteger)response.expectedContentLength;
_data = [NSMutableData dataWithCapacity:_expectedBytes];
// make a progress update here
}
You'll receive a call to the delegate method didReceiveData each time a chunk of data is received, so you know how much data you've received up to this point.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_data appendData:data];
_receivedBytes = _data.length;
// make a progress update here
}