如何完美地从IOS应用程序注销?

4
以下代码可以工作,但存在一个bug。场景是这样的:我首先登录进入应用程序系统。一旦登录成功,应用程序将设置UserDefaults(UserId)。之后,我可以使用存储的UserId导航应用程序视图。当我进入设置并点击注销时,它将清除UserId并跳转到登录视图。
BUG: 当我再次登录到应用程序并单击主屏幕按钮返回iPhone桌面并关闭应用程序,然后再次打开它时,它仍会存储UserId。因此,如果我进入设置并注销,它将清除UserId并不会跳转到登录视图。我不知道为什么。
代码:
- (IBAction)resetKeychain:(id)sender {

    UIActionSheet *actionSheet = [[UIActionSheet alloc] 
                 initWithTitle:@"Are you sure you want to logout?" 
                 delegate:self 
                 cancelButtonTitle:@"Cancel" 
                 destructiveButtonTitle:@"Logout"
                 otherButtonTitles:nil];
    actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
    [actionSheet showFromTabBar:self.tabBarController.tabBar];
    [actionSheet release];

}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex ==0) {
        //logout
        NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
        //delete user ID fro user Defaults
        [defaults setObject:nil forKey:@"UserId"];
        //redirect to login view

        NewClassMoonAppDelegate * appsDelegate =[[UIApplication sharedApplication] delegate];
        [appsDelegate.window addSubview:[appsDelegate.login view]];

    }
}

2
没有所谓的“完美解决方案”。记住,最好往往是好的敌人。 - Eric
3个回答

8

根据我理解你的问题,需要进行格式化和整理,我认为:

a) 你的@"UserID"值没有与NSUserDefaults同步,因为你没有调用-synchronize方法。NSUserDefaults会更新其内存中的键值存储,但不会将其写入磁盘,这意味着它会在任意时间丢失。

b) 它没有到达loginView可能与几个原因有关,最有可能的是它已经是你的UIWindow的子视图。因此,不要在应用程序委托中重用login属性,而是创建一个新的View Controller实例变量,并将其设置为rootViewController

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (buttonIndex == 0) {
        NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:nil forKey:@"UserId"];
        [defaults synchronize];
        //redirect to login view

        NewClassMoonAppDelegate * appsDelegate =[[UIApplication sharedApplication] delegate];
        LoginViewController *login = [[LoginViewController alloc] initWithNibName...];
        [appsDelegate.window setRootViewController:nil];
        [appsDelegate.window setRootViewController:login];

    }
}

嘿max_,你的解决方案很棒,但我有一个疑问,我需要在退出应用程序之前从内存中删除所有其他加载过的MVC吗?如果不删除,那么这些MVC会怎样?它们会一直存在于内存中吗?应该如何处理这种情况? - RockandRoll
由rootViewController呈现的任何内容以及rootViewController本身将从内存中释放。 这不会立即发生,因为您可能在应用程序中另外保留了引用,或者编译器可能还没有准备好这样做。 - max_

1

Swift:

max_的回答中进行了一些更改:

let objectsToSave: [String] = [obj1, obj2, obj3]
for key in objectsToSave {
    NSUserDefaults.standardUserDefaults().removeObjectForKey(key)
}

 let appsDelegate = UIApplication.sharedApplication().delegate
 let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
 let newLoginVC: LoginViewController = storyboard.instantiateInitialViewController() as! LoginViewController
 appsDelegate?.window!!.rootViewController = nil
 appsDelegate?.window!!.rootViewController = newLoginVC

编辑:我所做的唯一更改就是通过故事板初始化newLoginVC,而不是使用initWitName


请进一步解释一下,为什么要进行更改以及您希望通过更改实现什么。 - davejal
这个解决方案可以导航回到loginVC,但是当注销发生时,为前一个用户会话分配的视图控制器并没有被释放。我们如何释放所有视图控制器? - Chris

0
将 UINavigation controller 的 property 合成,并在退出按钮下面写入以下代码。
AppDelegate * appDelegateObj =[[UIApplication sharedApplication] delegate];
    login *loginObj = [[login alloc]initWithNibName:@"login" bundle:nil];
    [appDelegateObj.window setRootViewController:nil];
    navObj=[[UINavigationController alloc]initWithRootViewController:loginObj];
    [appDelegateObj.window setRootViewController:navObj];

为什么需要 UINavigationController?OP没有在导航堆栈中呈现登录控制器。除此之外,我没有看到其他已发布答案的任何补充。 - UditS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接