你说的对。将此功能构建到视图控制器中是不必要的,而且封装很差。
在 MVC 范式中,模型通常具有数据上下文。数据上下文管理与后端存储的通信(在 iOS 中,这往往是 Web 服务或本地文件)以填充和归档模型对象。对于经过身份验证的数据上下文,您拥有用户名、密码和身份验证状态的属性。
@interface DataContext : NSObject
//Authentication
@property (nonatomic, strong) NSString * username;
@property (nonatomic, strong) NSString * password;
@property (nonatomic, assign) NSInteger authenticationState;
-(void)login;
//Data object methods from authenticated data source (web service, etc)
-(NSArray *)foos;
-(NSArray *)bars;
@end
如果要跟踪许多状态(已验证、未验证、尝试使用存储的凭据进行验证后未验证),已验证状态可以是简单的布尔值或整数。您现在可以观察该authenticationState
属性以允许您的控制器层对身份验证状态的更改采取措施。
从您的 Web 服务请求数据时,当服务器由于凭据无效而拒绝请求时,您会更改身份验证状态
-(NSArray *)foos
{
NSArray * foos = nil;
//Here you would make a web service request to populate the foos array from your web service.
//Here you would inspect the status code returned to capture authentication errors
//I make my web services return status 403 unauthorized when credentials are invalid
int statusCode = 403;
if (statusCode == 403)
{
self.authenticationState = 0;//Unauthorized
}
return foos;
}
Controller 是您的应用程序委托。它存储我们的 DataContext 的实例。它观察对该authenticated
属性的更改并在适当时显示视图或重新尝试身份验证。
- (void)observeAuthenticatedState:(NSNotification *)notification
{
DataContext * context = [notification object];
if (context.authenticatedState == 0)//You should have constants for state values if using NSIntegers. Assume 0 = unauthenticated.
{
[self.context login];
}
if (context.authenticatedState == -1)//You should have constants for state values if using NSIntegers. Assume -1 = unauthenticated after attempting authentication with stored credentials
{
UIViewController * loginController = nil;//Instantiate or use existing view controller to display username/password to user.
[[[self window] rootViewController] presentViewController:loginController
animated:YES
completion:nil];
}
if (context.authenticatedState == 1)//authenticated.
{
[[[self window] rootViewController] dismissViewControllerAnimated:YES
completion:nil];
}
}
在您的故事板中,您基本上可以假装身份验证不存在,因为您的应用程序委托会在数据上下文传达需要时插入用户界面进行身份验证。