使用标签栏控制器(故事板)阻止对UIViewControllers的访问

时间:2012-04-17 01:56:35

标签: objective-c ios authentication uiviewcontroller uistoryboard

我目前遇到iOS应用程序的问题 我试图采用渐进的登录模式,即:使用可以访问某些应用程序而无需登录。

所需功能如下:

  • 用户可以随时查看所有需要登录的导航项目
  • 当用户尝试访问需要登录的uiview(控制器)时,系统会提示他们使用UIAlertView要求他们登录。(当应用程序识别出已启动的segue目的地受限制时,最好显示UIAlertView。) / LI>

首先,我使用了UIViewController的子类,在指定的初始化程序(initWithCoder)中,它将检查NSUserDefaults以查看用户是否已登录。然后我将其子类化。限制如下:

  • 无法使用UIViewController的其他子类,即UITableViewController
  • UIAlertView在视图出现后出现,我假设如果子类UIViewController假定用户已登录,则会导致错误。

问题摘要:
我想知道如何有条件地阻止用户访问UIViewController的某些UIView(Controller)和子类,当发生这种情况时会出现UIAlertView。

更新1
类别和/或协议是否可行?

更新2
CodaFi指出单身人士是管理用户状态的绝佳解决方案。

实现后,我现在需要弄清楚如何控制用户的访问权限 当我使用故事板时,我觉得最通用的实现将是子类化UIStoryboardSegue,并且在执行方法检查用户是否正在尝试访问受限制的UIViewController(可能受限制的控制器具有指定所需状态的协议属性:登录/出)。但是,这里的缺陷是您无法在故事板图形编辑器中选择UIStoryboardSegue的类/子类。我知道我可以以编程方式进行,但是这似乎很乏味,因为我必须添加IBActions并将其添加到执行segues的方法中,而且我认为这不会适用于navigationController和tabbarControllers等元素的行为方式。

是否有人有可行的解决方案来限制用户的导航?

更新3
我已经添加了这个问题的答案,但是我仍然认为它没有答案,因为我写的答案没有考虑导航栏控制器之间的段落。但是它可能会帮助一些人。

2 个答案:

答案 0 :(得分:2)

所以,我已经使用自定义segues回答了如何做到这一点。

现在我明白我的真正问题是与tabbarcontrollerdelegate协议的精神脱节。

作为防止访问选项卡的解决方案,我已经创建了一个类来处理所述标签栏控制器

#import <Foundation/Foundation.h>

@interface TabBarDelegate : NSObject<UITabBarControllerDelegate,UIAlertViewDelegate>{
    UITabBarController *cachedTabBarController;
}

@end

#import "TabBarDelegate.h"

@implementation TabBarDelegate

-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
    NSLog(@"%s",__FUNCTION__);
    NSLog(@"Pretending the user isnt logged in");

    if(true){
        NSString *message = [NSString stringWithFormat:@"You require an account to access %@",viewController.tabBarItem.title];
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Account Required" message:message delegate:self cancelButtonTitle:@"Okay" otherButtonTitles: @"Login",@"Create Account",nil];
        [alert show];
        //Hold tabbarcontroller property for alert callback
        cachedTabBarController = tabBarController;
        return false;
    }

    return true;
}

-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
    if(cachedTabBarController){
        switch (buttonIndex) {
            case 1:
                //Login
                [cachedTabBarController performSegueWithIdentifier:@"tabBarToLogin" sender:cachedTabBarController];
                break;
            case 2:
                //Sign up
                [cachedTabBarController performSegueWithIdentifier:@"tabBarToSignup" sender:cachedTabBarController];
                break;
            default:
                break;
        }
        //Release tab bar controller from memory
        cachedTabBarController = nil;
    }
}

@end

然后我将它连接到applicationDidFinishLaunching中的appDelegate ......

//Hook up tab bar delegate
    mainTabController = (UITabBarController*)self.window.rootViewController;
    mainTabBarDelegate = [[TabBarDelegate alloc] init];
    mainTabController.delegate = mainTabBarDelegate;

和Voila

答案 1 :(得分:0)

好的,我有一部分解决方案。

它仅适用于您可以选择自定义segue的情况(我只编写推送代码而非模态代码)。

对于需要身份验证的所有控制器的协议“UIViewControllerAuthentication”,此协议包含一种检索所需身份验证状态的方法。

enum authenticationStatus {
notLoggedIn = 0,
noPassword = 1,
loggedIn = 2
};

@protocol UIViewControllerAuthentication <NSObject>

-(enum authenticationStatus)authStatusRequired;

@end

需要身份验证的控制器符合此协议:

-(enum authenticationStatus)authStatusRequired{
return loggedIn;
}

然后将其用于经过身份验证的push segue

@interface SeguePushWithAuth : UIStoryboardSegue

@end
-(void)perform{
    NSLog(@"custom segue destination : %@",self.destinationViewController);
    NSLog(@"custom segue source : %@",self.sourceViewController);
    NSLog(@"custom segue dest conforms to protocol : %i",[self.destinationViewController conformsToProtocol:@protocol(UIViewControllerAuthentication)]);

    if([self.destinationViewController conformsToProtocol:@protocol(UIViewControllerAuthentication)]){
        UIViewController <UIViewControllerAuthentication> *destination = (UIViewController <UIViewControllerAuthentication> *)self.destinationViewController;
        if (!((int)[AccountModel userAuthStatus] >= (int)[destination authStatusRequired])) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Authentication" message:@"You need an account to access this area" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Login",@"Create Account", nil];
            //alert
            [alert show];
            return;
        }
    }

    [[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:true];
}

@end

然后在uistoryboard中使用自定义segue

这是一个很好的模式,允许目标控制器取消segue 然而,它远非我想要的,因为我希望能够验证将标签栏控制器链接到他们的孩子的segues。