I'm trying to get my iOS app to access files from my local apache server using basic authentication. Everything works fine from the browser and I have to enter my username and password to access an image in the restricted folder. However in the app some strange things are happening.
I make an NSURLConnection to the server (which is all working fine) and the first time my request is made the delegate method - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge is called. For test purposes I respond with an empty NSURLCredential and obviously the connection fails. However when I make the request again the delegate method isn't called and somehow the image gets downloaded and displayed without any authentication. I'm really confused as to what's going on!
Here is some of the code:
- (IBAction)loginPressed
{
self.username = self.usernameField.text;
self.password = self.passwordField.text;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://192.168.0.2/secret/favicon.ico"]];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
{
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.imageView.image = [UIImage imageWithData:self.data];
self.errorLabel.text = #"";
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:self.username password:self.password persistence:NSURLCredentialPersistenceNone];
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
self.errorLabel.text = #"Invalid Username and/or Password";
self.imageView.image = [UIImage imageWithData:[[NSData alloc] init]];
}
}
You should use a different delegate callback, connection:didReceiveAuthenticationChallenge:.
- (void) connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] > 0) {
// Do something, like prompt for credentials or cancel the connection
} else {
NSURLCredential *creds = [NSURLCredential
credentialWithUser:#"someUser"
password:#"somePassword"
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:creds forAuthenticationChallenge:challenge];
}
}
Related
I have followed a handful of examples on NSURLConnection, see latest below, but yet I keep getting null on the returned FinishLoading. I checked didReceiveResponse and its getting the data. What am I not doing right here?
EDITED: Now works as expected.
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_dataDictionary = [NSMutableDictionary new];
_theReceivedData = [NSMutableData new];
[_theReceivedData setLength:0];
// add object
[_dataDictionary setObject:_theReceivedData forKey:[connection description]];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSMutableData *imageData = _dataDictionary[ [connection description] ];
[imageData appendData:data];
if([connection description]!=nil && imageData!=nil)
{
[_dataDictionary setObject:imageData forKey:[connection description]];
}
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSData *imageData = _dataDictionary[ [connection description] ];
if(imageData!=nil)
{
NSLog(#"%#",imageData);
Take NSMutableData *theReceivedData out. Make it a class variable. Your problem is theReceivedData is being deallocated in every method. You are creating a new object in every method. Retain the old one.
NSMutableData *_theReceivedData;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_theReceivedData = [NSMutableData new];
[_theReceivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_theReceivedData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
// LOOK AT THIS http://stackoverflow.com/questions/1064920/iphone-corrupt-jpeg-data-for-image-received-over-http
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"%#",_theReceivedData);
I have a "traditional" enterprise iPad application that needs to make many different web service calls over its lifetime using NTLM authentication. Upon start up of the application, I anticipate getting the user name and password off of a keychain (which the app saves the first time its used since the keychain does not have the user name and subsequently is updated when the password fails to work due to updates).
On startup, various web service calls are needed to get initial data for the application. The user then will be presented with a tabbed controller to choose the functionality they want which in turn will, of course, do more web service calls.
I believe I have a tactic for dealing with each class receiving data through a custom data delegate as presented in this StackOverflow answer (How do you return from an asynchronous NSURLConnection to the calling class?). However, I'm still a bit confused as to how to properly use the -(void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge functionality.
In didReceiveAuthenticationChallenge, I have code like this
[[challenge sender] useCredential:[NSURLCredential credentialWithUser:#"myusername"
password:#"mypassword"
persistence:NSURLCredentialPersistencePermanent]
forAuthenticationChallenge:challenge];
Since I'm setting permanent persistence, I would expect to not to have to constantly pass in the user name and password in the functionality. Is there a pattern that's used to initially setup the user's NTLM credentials (and/or check to see if they're already there) and then just use the "permanent" credentials for subsequent web service calls?
Also, as a secondary question/part to this. What is the appropriate/elegant approach to passing around a username/password throughout an Objective-C application? I'm thinking either global var's or a singleton instance (which seems a bit overkill for just a couple of needed var's).
It has been awhile since we've tackled this issue and successfully solved it. I thought it was time to put up the answer here. The code below belongs in its own class and will not work quite out of the box but should get you a long ways towards what you need. For the most part, it all should work fine, but you'll just need to make sure the various areas such as alert views, data stores, etc. are all set up the way you need.
A major stumbling block in our understanding of the way that Objective-C & iOS deals with NTLM communications is figuring out its normal process of communicating with a URL.
First contact with a URL is done anonymously. Of course, in a Windows secure environment this will fail. This is when the application will attempt to contact the URL again but this time with any credentials it has for that URL already on the keychain and utilize the willSendRequestForAuthenticationChallenge method. This was very confusing for us since this method didn't fire until AFTER the first call failed. It finally dawned on us what was happening with that first call being anonymous.
Part of the pattern you'll see here is that the connection will be attempted with any credentials already on the keychain. If those fail/missing, then we will popup a view that requests the user to enter the username and password and then we retry with that.
There's a number of idiosyncrasies that we needed to account for as you'll see throughout the code. It took many iterations and lots of testing to get this stable. Much of this was based on patterns that have been posted all over the internet for doing pretty much what we were trying to do but didn't quite take us all the way there.
The code we did generalizes GET/POST calls. This is my first major code post to StackOverflow and my apologies if I'm missing some conventions and I'll correct what I need to when brought to my attention.
#import "MYDataFeeder.h"
#import "MYAppDelegate.h"
#import "MYDataStore.h"
#import "MYAuthenticationAlertView.h"
#import "MYExtensions.h"
#interface MYDataFeeder () <NSURLConnectionDelegate>
#property (strong, nonatomic) void (^needAuthBlock)(NSString *, NSString *);
#property (strong, nonatomic) void (^successBlock)(NSData *);
#property (strong, nonatomic) void (^errorBlock)(NSError *);
#end
#implementation MYDataFeeder{
NSMutableData *_responseData;
NSString *_userName;
NSString *_password;
NSString *_urlPath;
BOOL _hasQueryString;
}
+ (void)get: (NSString *)requestString
userName: (NSString *)userName
password: (NSString *)password
hasNewCredentials: (BOOL)hasNewCredentials
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock
{
MYDataFeeder *x = [[MYDataFeeder alloc] initWithGetRequest:requestString userName:userName password:password hasNewCredentials:hasNewCredentials successBlock:successBlock errorBlock:errorBlock needAuthBlock:needAuthBlock];
}
+ (void)post: (NSString *)requestString
userName: (NSString *)userName
password: (NSString *)password
hasNewCredentials: (BOOL)hasNewCredentials
jsonString: (NSString *)jsonString
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock
{
MYDataFeeder *x = [[MYDataFeeder alloc] initWithPostRequest:requestString userName:userName password:password hasNewCredentials:hasNewCredentials jsonString:jsonString successBlock:successBlock errorBlock:errorBlock needAuthBlock:needAuthBlock];
}
- (instancetype)initWithGetRequest: (NSString *)requestString
userName: (NSString *)userName
password: (NSString *)password
hasNewCredentials: (BOOL)hasNewCredentials
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock
{
return [self initWithRequest:requestString userName:userName password:password hasNewCredentials:hasNewCredentials isPost:NO jsonString:nil successBlock:successBlock errorBlock:errorBlock needAuthBlock:needAuthBlock];
}
-(instancetype)initWithPostRequest: (NSString *)requestString
userName: (NSString *)userName
password: (NSString *)password
hasNewCredentials: (BOOL)hasNewCredentials
jsonString: (NSString *)jsonString
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock
{
return [self initWithRequest:requestString userName:userName password:password hasNewCredentials:hasNewCredentials isPost:YES jsonString:jsonString successBlock:successBlock errorBlock:errorBlock needAuthBlock:needAuthBlock];
}
//Used for NTLM authentication when user/pwd needs updating
- (instancetype)initWithRequest: (NSString *)requestString
userName: (NSString *)userName
password: (NSString *)password
hasNewCredentials: (BOOL)hasNewCredentials
isPost: (BOOL)isPost
jsonString: (NSString *)jsonString
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock //delegate:(id<MYDataFeederDelegate>)delegate
{
self = [super init];
requestString = [requestString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
if(self) {
if (!errorBlock || !successBlock || !needAuthBlock) {
[NSException raise:#"MYDataFeeder Error" format:#"Missing one or more execution blocks. Need Success, Error, and NeedAuth blocks."];
}
_responseData = [NSMutableData new];
_userName = userName;
_password = password;
_successBlock = successBlock;
_hasNewCredentials = hasNewCredentials;
_errorBlock = errorBlock;
_needAuthBlock = needAuthBlock;
NSString *host = [MYDataStore sharedStore].host; //Get the host string
int port = [MYDataStore sharedStore].port; //Get the port value
NSString *portString = #"";
if (port > 0) {
portString = [NSString stringWithFormat:#":%i", port];
}
requestString = [NSString stringWithFormat:#"%#%#/%#", host, portString, requestString];
NSURL *url = [NSURL URLWithString:requestString];
NSString *absoluteURLPath = [url absoluteString];
NSUInteger queryLength = [[url query] length];
_hasQueryString = queryLength > 0;
_urlPath = (queryLength ? [absoluteURLPath substringToIndex:[absoluteURLPath length] - (queryLength + 1)] : absoluteURLPath);
NSTimeInterval timeInterval = 60; //seconds (60 default)
NSMutableURLRequest *request;
if (isPost) {
request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:timeInterval];
NSData *requestData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)requestData.length] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
[request setHTTPShouldHandleCookies:YES];
}
else {
request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:timeInterval];
}
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
return self;
}
- (instancetype)initWithRequest: (NSString *)requestString
successBlock: (void (^)(NSData *))successBlock
errorBlock: (void (^)(NSError *))errorBlock
needAuthBlock: (void (^)(NSString *, NSString *))needAuthBlock //delegate:(id<MYDataFeederDelegate>)delegate
{
return [self initWithRequest:requestString userName:NULL password:NULL hasNewCredentials:NO isPost:NO jsonString:nil successBlock:successBlock errorBlock:errorBlock needAuthBlock:needAuthBlock]; //delegate:delegate];
}
#pragma mark - Connection Events
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return YES;
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection {
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (response){
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger code = httpResponse.statusCode;
if (code == 401){
NSLog(#"received 401 response");
[MYAuthenticationAlertView showWithCallback:_needAuthBlock];
[connection cancel];
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
_successBlock(_responseData);
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
_errorBlock(error);
}
- (void) connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM])
{
BOOL hasConnectionCredentials = [[MYDataStore sharedStore] hasConnectionCredentials]; //Determines if there's already credentials existing (see method stub below)
long previousFailureCount = [challenge previousFailureCount];
BOOL hasFailedAuth = NO;
//If the application has already gotten credentials at least once, then see if there's a response failure...
if (hasConnectionCredentials){
//Determine if this URL (sans querystring) has already been called; if not, then assume the URL can be called, otherwise there's probably an error...
if ([[MYDataStore sharedStore] isURLUsed:_urlPath addURL:YES] && !_hasQueryString){
NSURLResponse *failureResponse = [challenge failureResponse];
if (failureResponse){
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)[challenge failureResponse];
long code = [httpResponse statusCode];
if (code == 401){
hasFailedAuth = YES;
}
}
}
}
else{
//Need to get user's credentials for authentication...
NSLog(#"Does not have proper Credentials; possible auto-retry with proper protection space.");
}
/* This is very, very important to check. Depending on how your security policies are setup, you could lock your user out of his or her account by trying to use the wrong credentials too many times in a row. */
if (!_hasNewCredentials && ((previousFailureCount > 0) || hasFailedAuth))
{
NSLog(#"prompt for new creds");
NSLog(#"Previous Failure Count: %li", previousFailureCount);
[[challenge sender] cancelAuthenticationChallenge:challenge];
[MYAuthenticationAlertView showWithCallback:_needAuthBlock];
[connection cancel];
}
else
{
if (_hasNewCredentials){
//If there's new credential information and failures, then request new credentials again...
if (previousFailureCount > 0) {
NSLog(#"new creds failed");
[MYAuthenticationAlertView showWithCallback:_needAuthBlock];
[connection cancel];
} else {
NSLog(#"use new creds");
//If there's new credential information and no failures, then pass them through...
[[challenge sender] useCredential:[NSURLCredential credentialWithUser:_userName password:_password persistence:NSURLCredentialPersistencePermanent] forAuthenticationChallenge:challenge];
}
} else {
NSLog(#"use stored creds");
//...otherwise, use any stored credentials to call URL...
[[challenge sender] performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
}
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { // server trust challenge
// make sure challenge came from environment host
if ([[MYDataStore sharedStore].host containsString:challenge.protectionSpace.host]) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
else {
// request has failed
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
#end
-(BOOL) hasConnectionCredentials
{
NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
return ([credentialsDict count] > 0);
}
//Sample use of Data Feeder and blocks:
-(void)myMethodToGetDataWithUserName:(NSString*)userName password:(NSString*)password{
//do stuff here
[MYDataFeeder get:#"myURL"
userName:userName
password:password
hasNewCredentials:(userName != nil)
successBlock:^(NSData *response){ [self processResponse:response]; }
errorBlock:^(NSError *error) { NSLog(#"URL Error: %#", error); }
needAuthBlock:^(NSString *userName, NSString *password) { [self myMethodToGetDataWithUserName:username withPassword:password]; }
];
}
//The needAuthBlock recalls the same method but now passing in user name and password that was queried from within an AlertView called from within the original DataFeeder call
I am using AWSS3 to upload my media to amazon.
This is how I am doing:
Bool uploaded = NO;
dispatch_async("my.queue.whatever", ^{
NSData *mediaData = UIImagePNGRepresentation(mediaImage);//mediaImage of type uiimage
NSString *pictureName = #"randomstring";
AmazonCredentials *amazonCredentials = [[AmazonCredentials alloc] initWithAccessKey:#"myAccessKey" withSecretKey:#"mySecretKey" withSecurityToken:#"mySessionToken"];
AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithCredentials:amazonCredentials];
S3PutObjectRequest *s3Request = [[S3PutObjectRequest alloc] initWithKey:pictureName inBucket:#"myPictureBucket"];
s3Request.delegate = self;
//s3Request.contentType = CONTENT_TYPE;
s3Request.cannedACL = [S3CannedACL publicRead];
s3Request.data = mediaData;
[s3Client putObject:s3Request];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!uploaded);
);
and these are my delegate functions:
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
{
uploaded = YES;
}
-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error{
uploaded = YES;
}
- (void)request:(AmazonServiceRequest *)request didFailWithServiceException:(NSException *)exception{
NSLog(#"didFailWithServiceException %#",[exception description]);
uploaded = YES;
}
- (void)request:(AmazonServiceRequest *)request didSendData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten totalBytesExpectedToWrite:(long long)totalBytesExpectedToWrite{}
-(void)request:(AmazonServiceRequest *)request didReceiveResponse:(NSURLResponse *)response{}
-(void)request:(AmazonServiceRequest *)request didReceiveData:(NSData *)data{}
and when the function didFailWithServiceException is called, it gives me the error: "Request timed out". I can't find anything in google. Need your help!! Thanks
Try to increase the default timeout:
s3Client.timeout = desiredtimeout;
I'm experimenting some problems with the upload operation, it starts to upload but after a couple of seconds the delegate is not called again.
request: didSendData: totalBytesWritten: totalBytesExpectedToWrite:
I don't know if there is some bug in the framework or in the Amazon servers, or it is just some bug in my code.
I never use web API and don't know what i may read about this. I read FAROO Return Values doc, but i don't understand how i may get result-array (or dictionary) in cocoa.
Please anybody give me example or tutorial how to use Faroo API (or other web API) in objective-c.
Thank you.
To use web API and FAROO API in particular i use NSURLConnection class and NSURLConnectionDelegate protocol:
- (IBAction)search:(id)sender {
NSString* requestString = [NSString stringWithFormat:#"http://www.faroo.com/api?q=%#&start=1&length=10&l=ru&src=news&f=xml&YOUR_API_KEY",[searchField stringValue]];
// NSLog(#"str %#",requestString);
NSURL* requestUrl = [NSURL URLWithString:requestString];
NSURLRequest* searchRequest = [NSURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestReloadRevalidatingCacheData timeoutInterval:60];
[self performSelectorOnMainThread:#selector(startConnectionWithRequest:) withObject:searchRequest waitUntilDone:NO];
}
- (void)startConnectionWithRequest:(NSURLRequest*)request {
NSURLConnection* connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
if (connection) {
//update GUI and do something...
theData = [NSMutableData data];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Receive data");
[theData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"Http status code %ld",(long)[httpResponse statusCode]);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Finish");
//do something with data and update GUI
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSAlert* searchFailedAlert = [NSAlert alertWithError:error];
[searchFailedAlert runModal];
}
One other way of doing things is to declare the missing method yourself as a category of the class in question. This will get the compiler to stop complaining about not finding the method, though of course you'll still need the runtime check you're already doing to avoid actually calling the method. You might also want to wrap such a declaration using availability macros, so that it will be ignored once you do move up to using the 10.5/10.6 SDK and you won't get a different compiler complaint down the line. That would look something like this:
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4 //ignore when compiling with the 10.5 SDK or higher
#interface NSPropertyListSerialization(MissingMethods)
+ (NSData *)dataWithPropertyList:(id)plist format:(NSPropertyListFormat)format options:(NSPropertyListWriteOptions)opt error:(NSError **)error;
#end
#endif
I'm working on a project for school, and I was wondering if there was a way to actually update the connection with NSURLConnection if a user submits something. For example, I'm having twitter search based on username, and I have a default username set up when the view loads. What would I have to do to refresh that connection when a user enters a different username on that page? I have my button handlers all set up, and I'm using the same code as in my viewDidLoad function. Is there a method call or something that will actually reset the connection?
Thanks,
David
I attached example codes
// member variable 'conn'
// NSURLConnection *conn;
// #property(strong, nonatomic) NSURLConnection *conn;
-(void)viewDidLoad {
[super viewDidLoad];
[self sendRequest];
}
- (IBAction)sendButtonClicked {
[self sendRequest];
}
- (void)sendRequest {
if (self.conn) {
[self.conn cancel];
self.conn = nil;
}
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
self.conn = conn;
[conn start];
}
// NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// append received data
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// error handling
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// using data
}
I don't think you can "reset" the connection. You will have to make a new request. In your button clicked method simply make a new request call with the new user name.
It works like a request in a browser, when you change some parameter in the url the browser sends of a new request to the web-server.
have a look at this example by apple (if you dont need the caching part just focus on URLCacheConnection.h/.m) http://developer.apple.com/library/ios/#samplecode/URLCache/Listings/Classes_URLCacheController_m.html#//apple_ref/doc/uid/DTS40008061-Classes_URLCacheController_m-DontLinkElementID_10
i