I am trying to use NSURLProtocol to handle authentication challenges for every NSURLSession connection . I used
[NSURLProtocol registerClass:[CustomHTTPSProtocol class]]
for NSURLConnection .But it is not working with NSURLSession so i need to setSessionConfiguration.protocolClasses=#[[CustomHTTPSProtocol class]];.
The problem is i use this URLProtocol class to only handle authentication challenges and i get received data's in the delegates of original class.
Something like this
OriginalClass
NSURLConnection
-(void)sendURL
{
[NSURLProtocol registerClass:[CustomHTTPSProtocol class]]; //done globally in didFinishLaunching
self.URL =[NSURL URLWithString:[[NSString stringWithFormat:#"https://www.google.co.in"]stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:self.URL];
self.connection=[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSlog(#"received data...%#",data);
}
NSURLSession
-(void)sendURL
{
self.URL =[NSURL URLWithString:[[NSString stringWithFormat:#"https://www.google.co.in"]stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:self.URL];
sessionConfiguration =[NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.protocolClasses=#[[CustomHTTPSProtocol class]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
NSURLSessionDataTask*task= [session dataTaskWithRequest:checkInInfoRequest];
[task resume];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
NSLog(#"data ...%# ",data); //handle data here
}
NSURLProtocol Class
NSURLConnection
-(void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:CustomHTTPSProtocolHandledKey inRequest:newRequest];
self.connection=[NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else
{
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
NSURLSession
- (void) startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:CustomHTTPSProtocolHandledKey inRequest:newRequest];
NSURLSession*session=[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
self.sessionTask=[session dataTaskWithRequest:newRequest];
[self.sessionTask resume];
}
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
}
Using the above logic i was able to handle authentication for all request globally and handling response individually. But with NSURLSession if i use NSURLProtocol, authentication is done in Protocol class but i am not able to receive data, since my original class delegates are not called.
Somebody help me out.
When you implement making the request yourself (or resend it as you did), your protocol becomes the challenge sender. You are responsible for creating an NSURLAuthenticationChallenge object, setting yourself as the sender, providing all the other bits from the existing challenge, and sending it using the NSURLProtocolClient class.
Take a look at Apple's CustomHTTPProtocol Sample Code project for examples and further information.
Related
I'm trying to load a self signed website. I know I can use NSURLConnection to give credential by using this code
UIWebView to view self signed websites (No private api, not NSURLConnection) - is it possible?
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
[challenge.sender useCredential: [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
}
and load the request in
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.webviewVc.webview loadRequest:_FailedRequest];
}
But when I try to use NSURLSession to do the similar thing, I'm always getting the error
NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
My code looks like this
- (BOOL)loadWithRequest:(NSURLRequest *)request
{
if (!_Authenticated ) {
_FailedRequest = request;
NSURLSessionConfiguration* defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:nil];
NSURLSessionDataTask * task = [session dataTaskWithRequest:_FailedRequest];
[task resume];
return NO;
}
_Authenticated = NO;
return YES;
}
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
[self.webviewVc.webview loadRequest:_FailedRequest];
}
Any idea?
Thanks
My application uses NSURLConnection to communicate with server. We use https for communication. In order to handle authentication from all request in one place i used NSURLProtocol and handled authentication in delegates in that class. Now I have decided to use NSURLSession instead of NSURLConnection. I am trying do get NSURLProtocol working with NSURLSession
I created a task and used NSURLProtocol by
NSMutableURLRequest *sampleRequest = [[NSMutableURLRequest alloc]initWithURL:someURL];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.protocolClasses = #[[CustomHTTPSProtocol class]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *task = [session dataTaskWithRequest:checkInInfoRequest];
[task resume];
CustomHTTPSProtocol which is my NSURLProtocol class looks like this
static NSString * const CustomHTTPSProtocolHandledKey = #"CustomHTTPSProtocolHandledKey";
#interface CustomHTTPSProtocol () <NSURLSessionDataDelegate,NSURLSessionTaskDelegate,NSURLSessionDelegate>
#property (nonatomic, strong) NSURLSessionDataTask *connection;
#property (nonatomic, strong) NSMutableData *mutableData;
#end
#implementation CustomHTTPSProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([NSURLProtocol propertyForKey:CustomHTTPSProtocolHandledKey inRequest:request]) {
return NO;
}
return [[[[request URL]scheme]lowercaseString]isEqualToString:#"https"];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void) startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:CustomHTTPSProtocolHandledKey inRequest:newRequest];
NSURLSession*session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
self.connection = [session dataTaskWithRequest:newRequest];
[self.connection resume];
self.mutableData = [[NSMutableData alloc] init];
}
- (void) stopLoading {
[self.connection cancel];
self.mutableData = nil;
}
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
NSLog(#"challenge..%#",challenge.protectionSpace.authenticationMethod);
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else {
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
NSLog(#"data ...%# ",data); //handle data here
[self.mutableData appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (!error) {
[self.client URLProtocolDidFinishLoading:self];
}
else {
NSLog(#"error ...%# ",error);
[self.client URLProtocol:self didFailWithError:error];
}
}
#end
Start loading is called and also authentication challenge is done but stop loading is called immediately after that.
Error code -999 "Cancelled" is returned after some time. didReceiveData is not called.
Note:NSURLProtocol and the Authentication Process worked fine with NSURLConnection.
What am I missing ?? My Questions are
Registering [NSURLProtocol registerClass:[CustomHTTPSProtocol class]]; worked fine with NSURLConnection but how to Resister for NSURLProtocol Globally with NSURLSession ?.
Why are the requests getting failed in NSURLProtocol(same URL and logic worked withURLConnection) with URLSession and how to get NSURLProtocol working with URLSession ?.
Kindly help me and let me know if you want any more details.
Registering a custom NSURLProtocol with NSUrlsession is same as the way you do with NSURLConnection.
NSURLSession Api's (NSURLSessionDataTask and other task classes) when used with custom NSUrlProtocol fails to handle HTTP Authentication Challenges properly.
This was working as expected on iOS 7.x and is broken in iOS 8.x.Raised a apple radar and my radar was closed saying it was a duplicate of another radar and I Still see the original radar is still open. So I believe this issue is not yet fixed by apple as of today.
Hope I am not too late with the answer :)
I know this is old but the problem you are having is in your didReceiveChallenge method. You are ending the method by calling
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
or
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
What you need to be doing instead is using the completion handler to send your results. It would look like this:
completionHandler(.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
or
completionHandler(.PerformDefaultHandling, nil)
These are in Swift 2.0 but should translate nicely to Obj-C.
My vague recollection is that NSURLSession automatically uses any globally registered protocols. So you shouldn't need to register it again, but it also shouldn't hurt to do so.
I wonder if the URL request is getting copied, in which case your custom tagging might not work, and you might be seeing infinite recursion until it hits some internal limit. Have you tried setting a request header instead?
In iPad app, I need to connect to a server and download files that's using a self-signed SSL certificate with NSURLSession object in background mode:
static NSString *const URL = #"https://...";
- (void)testBackgroundDownloadTask {
if (self.downloadTask) {
return self;
}
self.session = [self backgroundSession];
NSURL *downloadURL = [NSURL URLWithString:URL];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
self.downloadTask = [self.session downloadTaskWithRequest:request];
[self.downloadTask resume];
}
- (NSURLSession *)backgroundSession{
static NSURLSession *sess = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:URL];
// Default configuration: working perfectly
//NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.sessionSendsLaunchEvents = YES;
//configuration.TLSMinimumSupportedProtocol = kSSLProtocolAll;
configuration.networkServiceType = NSURLNetworkServiceTypeBackground;
sess = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return sess;
}
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
NSURLProtectionSpace *protectionSpace = challenge.protectionSpace;
NSString *authMethod = protectionSpace.authenticationMethod;
if ([authMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
// obtain challenge, it working with NSURLSession in default session config
[self.challengeHandler handleChallenge:challenge onCompletion:^(id obj) {
NSURLCredential *c = (NSURLCredential *)obj;
if (c) {
[challenge.sender useCredential:c forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential, c);
}
else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}];
}
else if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
}
If I use defaultSessionConfiguration, my app after call didReceiveChallenge method perform successfully download file (call NSURLSesionDownloadDelegate methods
– URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:
– URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
– URLSession:downloadTask:didFinishDownloadingToURL:
But I use backgroundSessionConfiguration, after call didReceiveChallenge other delegate’s methods not called (file not downloading and didCompleteWithError not called)
Any ideas on how to resolve this problem?
Are you testing this in the background?
On your NSURLSessionDownloadDelegate, you should see what you get when you implement
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
NSLog(#"%s %# %#", __PRETTY_FUNCTION__, task.response, error);
}
If any of that stuff in –URLSession:didReceiveChallenge:completionHandler: is async, then you need to surround it with a UIApplication/UIBackgroundTaskIdentifier {begin,end}BackgroundTask..., or iOS will kill your background process when the stack pops.
I have an app that is production along with a development server that has a self signed certificate.
I am attempting to test NSURLSession and background downloading but can't seem to get past - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
When I use NSURLConnection I am able to bypass it using:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
NSLog(#"canAuthenticateAgainstProtectionSpace %#", [protectionSpace authenticationMethod]);
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(#"didReceiveAuthenticationChallenge %# %zd", [[challenge protectionSpace] authenticationMethod], (ssize_t) [challenge previousFailureCount]);
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
But I can't figure out how to get this to work with NSURLSession >:(
This is what I have currently (that doesn't work):
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
NSLog(#"NSURLSession did receive challenge.");
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
I also tried creating a category of NSURLSession that would allow any certificate for a host:
#import "NSURLRequest+IgnoreSSL.h"
#implementation NSURLRequest (IgnoreSSL)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host {
return YES;
}
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host {}
#end
Which also doesn't seem to help.
EDIT
I've updated this method to return:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
//Creates credentials for logged in user (username/pass)
NSURLCredential *cred = [[AuthController sharedController] userCredentials];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
}
Which still does nothing.
For me your first example is working fine. I have tested with the following code without problems (it is of course very insecure since it allows any server certificate).
#implementation SessionTest
- (void) startSession
{
NSURL *url = [NSURL URLWithString:#"https://self-signed.server.url"];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil)
{
NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data: %#",text);
}
else
{
NSLog(#"Error: %#", error);
}
}];
[dataTask resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
#end
Update: This is the class interface, the SessionTest class is the NSURLSessionDataDelegate, to start the data download you create a SessionTest object and call the startSession method.
#interface SessionTest : NSObject <NSURLSessionDelegate>
- (void) startSession;
#end
There's not enough information to suggest a concrete solution to your problem.
Here are some principal requirements:
Since you want a background task, ensure you created a suitable NSSession object through backgroundSessionConfiguration:. Using this class factory method is mandatory for getting background sessions.
For requests running in the background in a separate process, only upload and download tasks are supported. Note that, in your original code, you are using a data task.
Ensure you have properly implemented the delegate method application:handleEventsForBackgroundURLSession:completionHandler: in your App Delegate. When your app is not running, and when the session is running in its own process and requires credentials, iOS will restart your app in the background and the background session will call this delegate method. See also https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:handleEventsForBackgroundURLSession:completionHandler:
Disabling server trust evaluation should work as you tried in your first example. Use this for development only!
See also (https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW44)
I'm currently experimenting with the twitter streaming api and i'm trying to get a stream with NSURLConnection. As it doesn't work with twitter, i simplified everything and tried to get some source-code out of google's website, but this doesn't work neither.
The connection starts and ends, but without calling the didReceiveData delegate. I'm sure i'm missing something. Hope you guy's can help me!
In the header: #interface ViewController : UIViewController <NSURLConnectionDataDelegate, NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, NSURLAuthenticationChallengeSender>
And in the body:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLConnection *connection;
NSMutableURLRequest *request;
// Do any additional setup after loading the view, typically from a nib.
request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[request setHTTPMethod:#"GET"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
NSLog(#"Stream finished.");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Connection failed!");
}
A couple of thoughts.
Your declaration of connectionDidFinishLoading doesn't look right. The standard NSURLConnectionDataDelegate method does not have a destinationURL parameter:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
Given the presence of NSURLAuthenticationChallengeSender, if you're expecting a challenge (which you won't get with Google web site) then you'd obviously handle it accordingly:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// For example, if you have a userid/password to use, see if this is the first
// challenge, and then tell NSURLConnection to try using those credentials, and if
// it failed a second time, you might just cancel the authentication challenge.
if (challenge.previousFailureCount == 0) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:kUserID password:kPassword persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
By the way, you do not want to call start method when you use initWithRequest or connectionWithRequest. It's only needed if you do a simple initWithRequest:delegate:startImmediately: and instruct it to not startImmediately.
Anyway, I used the following and it works fine:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%s: %#", __FUNCTION__, dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"%s error=%#", __FUNCTION__, error);
}
Someone said here that it was their SOAP format
NSURLConnection delegate method: didReceiveData not called ...Why ?? (iPhone SDK)
This also may be what you are looking for
NSURLConnection didReceiveData not called
Your NSURLConnection local variable connection is going out of scope at the end of viewDidLoad. Add a property to your ViewController to hold the NSURLConnection variable in scope.