views:

353

answers:

3

I am trying to make Twitter work in my app and everything works fine except the code does not seem to recognize an error from Twitter. If the username/password are not valid, I get an error message through this function:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{
 NSString* strData = [[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSASCIIStringEncoding] autorelease];
 NSLog(@"Received data: %@", strData ) ;
 return ;
}

It prints: Received data: Could not authenticate you. .

However, the app continues to the post a tweet view I have and ignores the error. Obviously, I do not have something setup right to detect such an error from twitter so my question is how do I get Xcode to recognize an error like this? This uses basic http auth btw and don't mention anything about OAuth...just trying to get this to work for now.

    -(void) onLogin:(id)sender
    { 
 [loading1 startAnimating];

 NSString *postURL = @"http://twitter.com/account/verify_credentials.xml";
 NSMutableURLRequest *request = [ [ NSMutableURLRequest alloc ] initWithURL: [ NSURL URLWithString:postURL ] ];

 NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];

 if (!theConnection) 
 {
  UIAlertView* aler = [[UIAlertView alloc] initWithTitle:@"Network Error" message:@"Failed to Connect to twitter" delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
  [aler show];
  [aler release];
 } 

 else
 {
  receivedData = [[NSMutableData data] retain];
 }

 [request release];
    }

    -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
    if ([challenge previousFailureCount] == 0 && ![challenge proposedCredential]) 
 {
        NSURLCredential *newCredential;
        newCredential=[NSURLCredential credentialWithUser:txtUsername.text
                                                 password:txtPassword.text
                                              persistence:NSURLCredentialPersistenceNone];

        [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        } 
 else 
 {
  isAuthFailed = YES;
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        }
    } 
A: 

The method - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data is called zero or more times depending on how much data is available.

In the case of a web request, it is likely that it'll be called more than once. What you need to do is create an NSMutableData object and store it as an instance variable. Then when this method is called you need to append the new data to your NSMutableData object, like so:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //myMutableData should be an instance of NSMutableData and stored as an instance variable in your class. Don't forget to initialise it.
    [myMutableData appendData:data];
}

If you don't do this, you could be missing parts of the response.

I don't know exactly how your performing the request or what kind of response you're getting back, but ideally, you will want a response formatted in XML or JSON, and you should use a parser to turn the response into something you can use.

That way, you would be able to extract error codes, messages, etc and act upon them accordingly.

Finally, if you're going to be using Twitter from your application, consider using a prebuilt library like MGTwitterEngine. It'll save you a lot of grief and hassle. Also, even though you said not to mention it, MGTwitterEngine supports OAuth now, as well, which would save you having to patch your code once the basic auth is turned off.

Jasarien
i had something similar to the above post and what you have posted as well and it still never has previousfailurecount equal to anything but 0.
fraggleRockz
+1  A: 

Your delegate needs to implement...

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

Which should get call if the server you are trying to connect to requires authentication. Here's some example code from a program of mine...

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   
        if ([challenge previousFailureCount] == 0) {
            NSURLCredential *newCredential;
            newCredential=[NSURLCredential credentialWithUser:_username
                                        password:_password
                                        persistence:NSURLCredentialPersistenceNone];
            [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        } else {
            [[challenge sender] cancelAuthenticationChallenge:challenge];
            NSLog(@"Bad Username Or Password");
        }
    }
}
Staros
I have this in my code and it is not enough, still never hit the else
fraggleRockz
A: 

ok so I can now get an error response or a authentication response in xml. now, how do I say, use this response as a triggering factor for connectionDidFailWithError because if twitter send me back an error, I want to give an in-app error.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];

NSXMLParser* parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];

return;
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string
{
NSLog(@"response: %@", string);
}
fraggleRockz
Try looking into... - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)errorSame as above. Implement it and see what types of errors you get back.
Staros
ok, all working now, just was confused on how to make it fail out correctly.
fraggleRockz