以编程方式触发的segue会在成功

时间:2015-04-30 12:47:37

标签: ios objective-c iphone segue nsnotificationcenter

我将我的应用程序连接到其他API以登录用户。登录过程完成后,我使用NSNotificationCenter通知控制器成功登录,并让应用程序执行segue以将用户带到主菜单。这是我的代码:

//perform log in, or show error message
-(void)logInAttemptComplete:(NSNotification *)notification
{
Boolean loginSuccessful = (Boolean)[[notification userInfo] objectForKey:@"loginSuccessful"];

[SVProgressHUD dismiss];
//if the suer was successfully logged in, take him to the main menu
if(loginSuccessful)
{
    //go to the main menu
    [self performSegueWithIdentifier:@"logInSuccessfulSegue" sender:self];
}
else
{
    //copy error code and display appropriate error
    int errorCode = [[[notification userInfo] objectForKey:@"HTTP Message"] intValue];
    //404 no server, 401 wrong password/no user
    if(errorCode==401)
    {
        //create and show error alert view
        UIAlertView *loginErrorAlertView = [[UIAlertView alloc] initWithTitle:@"Log In Failure" message:@"Wrong credentials. Check your Username and/or Password." delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [loginErrorAlertView show];
    }
    else
    {
        //create and show error alert view
        UIAlertView *loginErrorAlertView = [[UIAlertView alloc] initWithTitle:@"Log In Failure" message:@"Failed to contact server, please try again later." delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [loginErrorAlertView show];
    }
}
}

问题是,如果第一次尝试登录失败,并且假设尝试成功登录需要X次尝试,那么segue执行X次。它当然最终会出现在主菜单上,但最终结果却很难看。任何想法如何解决这一问题?也许我应该避免使用segue并以编程方式将用户直接带到另一个控制器?

用答案编辑

所以我通过添加行

来犯了错误
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logInAttemptComplete:) name:@"logInNotification" object:nil];

按下登录按钮的功能。

我通过在登录尝试失败后删除观察者来修复它

if(loginSuccessful)
{
//go to the main menu
[self performSegueWithIdentifier:@"logInSuccessfulSegue" sender:self];
}
else
{

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"logInNotification" object:nil];

4 个答案:

答案 0 :(得分:1)

我会使用两种不同的通知,这段代码似乎比它应该更复杂。

您自己没有提供登录代码,所以我只能回答一般问题。创建两个通知(一个用于成功,一个用于登录失败)。登录控制器根据登录尝试的结果发送通知。

您将上述方法拆分为两种方法,这两种方法在发送任一通知时都会被调用。

您的代码可能如下所示:

[manager GET:stringWithURLforRequest parameters:nil success:^(AFHTTPRequestOperation *task, id responseObject) {

   // ...
   [[NSNotificationCenter defaultCenter] postNotificationName:@"LogInSuccessful" object:nil userInfo:nil];

} failure:^(AFHTTPRequestOperation *task, NSError *error) {

   // ...    
   [[NSNotificationCenter defaultCenter] postNotificationName:@"LogInFailure" object:nil userInfo:@{ @"HTTP Message":statusCodeNumber}];

}];

...而且你只需要添加另一个通知来监听你的其他视图控制器。如果你这样做,你就可以更加区分登录失败和成功(更好的语义)。

答案 1 :(得分:0)

如果userInfo中的 @“loginSuccessful”NSNumber,请使用:

BOOL loginSuccessful = [notification.userInfor[@"loginSuccessful"] booleanValue];

在原始代码中,如果对象不是nil(并且如果我理解它总是如此),那么你总是会获得值为 YES 的loginSuccessful,因为你检查了一个对象存在而不是它的值。

您在此行中使用NSNumber:

@{@"loginSuccessful":@YES}

@YES只是[NSNumber numberWithBool:YES]

的缩写

根据this header布尔只是 unsigned char 所以你要签署这个char的指针,它总是为真(不是NULL)。

答案 2 :(得分:0)

根据我的理解,你发送了关于成功的通知,如果有重试,它会被调用太多次。

单行解决方案是在成功方法中停止收听该通知。

所以你在这些方面有一些东西(伪代码)

- (void)loginAttempt:(NSNotifcation*)notif{
    if (success){
//Stop listening to that notification, so the method never gets called again
    performSegueWithIndetifier
    }else{

    //retry

    }
}

另一种脏的单行方式是保持一个尝试次数的ivar,如果该数字当前等于零,则只调用perform segue。

我认为我的解决方案可以解决您的问题,但是如果您有时间我建议您以一种只在需要调用或其他X次成功的回调被忽略时调用您的segue的方式来检查您的设计。一种简单的想象方法是在上次登录之前不重试是结果。所以你不要重试,直到你真的知道你是否失败了(这是暂停或成功或其他任何事情)

答案 3 :(得分:0)

找到它:

问题是,即使由于

而发送了失败的消息,控制器也会“监听”
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logInAttemptComplete:) name:@"logInNotification" object:nil];

在按下登录按钮的功能内。

我所要做的只是添加

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"logInNotification" object:nil];

之后的

if(loginSuccessful)
{
//go to the main menu
[self performSegueWithIdentifier:@"logInSuccessfulSegue" sender:self];
}
else
{

否则检查。