views:

309

answers:

2

Hello, I want that my app shows an actionsheet when the user presses on the "Tweet"-Button and the username or password is wrong. For my Twitterfunction I use the TwitterRequest.m/h from Brandon Trebitowski. If everthing works great and the username/password is right, this happens in my app:

        TwitterRequest * t = [[TwitterRequest alloc] init];
        (...);
        [t statuses_update:twittermessage.text delegate:self requestSelector:@selector(status_updateCallback:)];

        loadingActionSheet = [[UIActionSheet alloc] initWithTitle:@"Posting to Twitter..." delegate:nil 
                                                cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
        [loadingActionSheet showInView:self.view];
    }


    - (void) status_updateCallback: (NSData *) content {
        [loadingActionSheet dismissWithClickedButtonIndex:0 animated:YES];
        [loadingActionSheet release];
        NSLog(@"%@",[[NSString alloc] initWithData:content encoding:NSASCIIStringEncoding]);
    }

But how can I show an other actionsheet when the username/password was wrong? Here is the TwitterRequest.m:

#import "TwitterRequest.h"

@implementation TwitterRequest

@synthesize username;
@synthesize password;
@synthesize receivedData;
@synthesize delegate;
@synthesize callback;
@synthesize errorCallback;

-(void)friends_timeline:(id)requestDelegate requestSelector:(SEL)requestSelector{
    isPost = NO;
    // Set the delegate and selector
    self.delegate = requestDelegate;
    self.callback = requestSelector;
    // The URL of the Twitter Request we intend to send
    NSURL *url = [NSURL URLWithString:@"http://twitter.com/statuses/friends_timeline.xml"];
    [self request:url];
}

-(void)statuses_update:(NSString *)status delegate:(id)requestDelegate requestSelector:(SEL)requestSelector; {
    isPost = YES;
    // Set the delegate and selector
    self.delegate = requestDelegate;
    self.callback = requestSelector;
    // The URL of the Twitter Request we intend to send
    NSURL *url = [NSURL URLWithString:@"http://twitter.com/statuses/update.xml"];
    requestBody = [NSString stringWithFormat:@"status=%@",status];
    [self request:url];
}

-(void)request:(NSURL *) url {
    theRequest   = [[NSMutableURLRequest alloc] initWithURL:url];

    if(isPost) {
        NSLog(@"ispost");
        [theRequest setHTTPMethod:@"POST"];
        [theRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        [theRequest setHTTPBody:[requestBody dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
        [theRequest setValue:[NSString stringWithFormat:@"%d",[requestBody length] ] forHTTPHeaderField:@"Content-Length"];
    }

    theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {
        // Create the NSMutableData that will hold
        // the received data
        // receivedData is declared as a method instance elsewhere
        receivedData=[[NSMutableData data] retain];
    } else {
        // inform the user that the download could not be made
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    //NSLog(@"challenged %@",[challenge proposedCredential] );

    if ([challenge previousFailureCount] == 0) {
        NSURLCredential *newCredential;
        newCredential=[NSURLCredential credentialWithUser:[self username]
                                                 password:[self password]
                                              persistence:NSURLCredentialPersistenceNone];
        [[challenge sender] useCredential:newCredential
               forAuthenticationChallenge:challenge];

    } else {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        // inform the user that the user name and password
        // in the preferences are incorrect
        NSLog(@"Invalid Username or Password");
    }

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // this method is called when the server has determined that it
    // has enough information to create the NSURLResponse

    // it can be called multiple times, for example in the case of a
    // redirect, so each time we reset the data.
    // receivedData is declared as a method instance elsewhere
    //[receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    //NSLog([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    // append the new data to the receivedData
    // receivedData is declared as a method instance elsewhere
    [receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error
{
    // release the connection, and the data object
    [connection release];
    // receivedData is declared as a method instance elsewhere
    [receivedData release];

    [theRequest release];

    // inform the user
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);

    if(errorCallback) {
        [delegate performSelector:errorCallback withObject:error];
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // do something with the data

    if(delegate && callback) {
        if([delegate respondsToSelector:self.callback]) {
            [delegate performSelector:self.callback withObject:receivedData];
        } else {
            NSLog(@"No response from delegate");
        }
    } 

    // release the connection, and the data object
    [theConnection release];
    [receivedData release];
    [theRequest release];
}

-(void) dealloc {
    [super dealloc];
}


@end

Sorry for this stupid question, but I'm learning Objective-C and programming in general since just one week and I don´t know correctly how to interact from my ViewController with other classes.

+2  A: 

To implement an action sheet, you must first implement the UIActionSheetDelegate in the header file (include UIActionSheetDelegate in the @interface definition between the <>).

In your code you are going to display the action sheet and catch the actions from the button press. To display an action sheet, do the following:

UIActionSheet *actionSheet = [[UIActionSheet alloc]
                              initWithTitle:@"Choose one, por favor"
                              delegate:self
                              cancelButtonTitle:@"Cancel"
                              destructiveButtonTitle:nil
                              otherButtonTitles:@"Save Favorite", @"Email", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
actionSheet.cancelButtonIndex = 2;
[actionSheet showInView:self.view];
[actionSheet release];

To act on the button press, use the following method:

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    // the user clicked one of the OK/Cancel buttons
    NSLog(@"The button index is: %i", buttonIndex);

    switch (buttonIndex) {
        case 0:
            NSLog(@"Button 0");
            [self saveNew];
            break;
        case 1:
            NSLog(@"Button 1");
            [self sendEmail];
            break;
        case 2:
            NSLog(@"Button 2");
            break;
        default:
            break;
    }
}

Your other option is to use an alert -- for an incorrect username/password, this may be the best option. The alert is a modal box displayed in the center of the screen. To implement an alert, implement the UIAlertViewDelegate in your header file.

Sample alert code is as follows:

UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:@"Ouch!"
  message:@"Your message is placed here"
  delegate:self 
  cancelButtonTitle:@"OK" 
  otherButtonTitles: nil];
[alert show];   
[alert release];
iPhone Guy
A: 

if you want to react when the user receives a request for authentication, you need to work inside didReceiveAuthenticationChallenge.

specifically, right above this line:

newCredential=[NSURLCredential credentialWithUser:[self username]
                                             password:[self password]
                                          persistence:NSURLCredentialPersistenceNone];

is where you want to be getting the username and password from the user.

if you want to handle a failure on authentication, you wanna piggyback on the 'else' clause in the previousCountFailure if statement.

specifically, after this line is where you want to tell the user they failed:

[[challenge sender] cancelAuthenticationChallenge:challenge];
Oren Mazor
Thanks, but it doens´t work - I tried to make a bool as property in the TwitterRequst-Class, which will be set to FALSE, when the important else-clause wil be reached. In my other ViewController i made a if (BOOL == FALSE) {do something}, but he always read the BOOL as TRUE, even if the BOOL will be set to FALSE - I think the problem is, that he read the If (BOOL == FALSE)-quere faster then the other class set it to False. What can I make?
Flocked
why don't you actually show your error message IN the didReceiveAuthenticationChallenge function, rather than trying to use flags and deal with race conditions (since you're using network signalling the time it takes to accomplish anything isn't really deterministic)
Oren Mazor