我将我的应用程序连接到其他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];
答案 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
{
否则检查。