我的iPad应用程序上有一个Child Modal登录屏幕,我想将用户信息传递给父Split View Controller.
我正在考虑使用NSNotification,但我不知道这是否是将数据传回父母的最简单/最有效的方法.
谢谢!
艾伦
解决方法
NSURLConnectionDelegate
protocol的例子.连接到URL是一个复杂的任务,包括处理响应,遇到身份验证挑战,保存下载的数据和处理错误,连接和委托在连接的整个生命周期中处理这些阶段.
您可能已经注意到,Objective-C协议用于实现委托,而不会将创建的对象(在本例中为您的登录视图控制器)与创建它的对象(父视图控制器)紧密耦合.然后,登录视图控制器可以与可以接收其协议中定义的消息的任何对象进行交互,而不是依赖于任何特定的类实现.明天,如果您收到允许任何视图控制器显示登录视图的要求,则登录视图控制器将不需要更改.您的其他视图控制器可以实现其委托协议,创建和呈现登录视图,并将其分配给委托,而不必使登录视图控制器知道它们的存在.
Stack Overflow中的一些代理示例可能非常混乱,并且与内置框架中的内容非常类似.必须仔细选择协议的名称和接口,以及分配给每个对象的职责,以便最大化代码重用,并实现代码的目标.
您应该首先查看内置框架中的许多代理协议,以了解在代码中表达时的关系.这是另一个小例子,根据您的登录用例.希望你能发现,代表团的目的是明确的,所涉及的对象的作用和责任是明确的,并通过代码中的名字来表达.
首先,我们来看看LoginViewController的委托协议:
#import <UIKit/UIKit.h> @protocol LoginViewControllerDelegate; @interface LoginViewController : UIViewController // We choose a name here that expresses what object is doing the delegating @property (nonatomic,weak) id<LoginViewControllerDelegate> delegate; @end @protocol LoginViewControllerDelegate <NSObject> // The methods declared here are all optional @optional // We name the methods here in a way that explains what the purpose of each message is // Each takes a LoginViewController as the first argument,allowing one object to serve // as the delegate of many LoginViewControllers - (void)loginViewControllerDidLoginSuccessfully:(LoginViewController *)lvc; - (void)loginViewController:(LoginViewController *)lvc didFailWithError:(NSError *)error; - (void)loginViewControllerDidReceivePasswordResetRequest:(LoginViewController *)lvc; - (void)loginViewControllerDiDReceiveSignupRequest:(LoginViewController *)lvc; - (BOOL)loginViewControllerShouldAllowAnonymousLogin:(LoginViewController *)lvc; @end
登录控制器可以将多个事件传达给其代理,并请求其委托用于定制其行为的信息.它在执行中将事件与代理进行通信,作为其对用户操作的响应的一部分:
#import "LoginViewController.h" @interface LoginViewController () @property (weak,nonatomic) IBOutlet UIButton *anonSigninButton; @end @implementation LoginViewController - (void)viewDidLoad { [super viewDidLoad]; // Here we ask the delegate for information used to layout the view BOOL anonymousLoginAllowed = NO; // All our protocol methods are @optional,so we must check they are actually implemented before calling. if ([self.delegate respondsToSelector:@selector(loginViewControllerShouldAllowAnonymousLogin:)]) { // self is passed as the LoginViewController argument to the delegate methods // in this way our delegate can serve as the delegate of multiple login view controllers,if needed anonymousLoginAllowed = [self.delegate loginViewControllerShouldAllowAnonymousLogin:self]; } self.anonSigninButton.hidden = !anonymousLoginAllowed; } - (IBAction)loginButtonAction:(UIButton *)sender { // We're preteneding our password is always bad. So we assume login succeeds when allowed anonmously BOOL loginSuccess = [self isAnonymousLoginEnabled]; NSError *loginError = [self isAnonymousLoginEnabled] ? nil : [NSError errorWithDomain:@"domain" code:0 userInfo:nil]; // Fake concurrency double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime,dispatch_get_main_queue(),^(void){ // Notify delegate of failure or success if (loginSuccess) { if ([self.delegate respondsToSelector:@selector(loginViewControllerDidLoginSuccessfully:)]) { [self.delegate loginViewControllerDidLoginSuccessfully:self]; } } else { if ([self.delegate respondsToSelector:@selector(loginViewController:didFailWithError:)]) { [self.delegate loginViewController:self didFailWithError:loginError]; } } }); } - (IBAction)forgotPasswordButtonAction:(id)sender { // Notify delegate to handle forgotten password request. if ([self.delegate respondsToSelector:@selector(loginViewControllerDidReceivePasswordResetRequest:)]) { [self.delegate loginViewControllerDidReceivePasswordResetRequest:self]; } } - (IBAction)signupButtonAction:(id)sender { // Notify delegate to handle signup request. if ([self.delegate respondsToSelector:@selector(loginViewControllerDiDReceiveSignupRequest:)]) { [self.delegate loginViewControllerDiDReceiveSignupRequest:self]; } } - (BOOL)isAnonymousLoginEnabled { BOOL anonymousLoginAllowed = NO; if ([self.delegate respondsToSelector:@selector(loginViewControllerShouldAllowAnonymousLogin:)]) { anonymousLoginAllowed = [self.delegate loginViewControllerShouldAllowAnonymousLogin:self]; } return anonymousLoginAllowed; } @end
主视图控制器实例化并呈现登录视图控制器,并处理其委托消息:
#import "MainViewController.h" #import "LoginViewController.h" #define LOGGED_IN NO @interface MainViewController () <LoginViewControllerDelegate> @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; // Fake loading time to show the modal cleanly if (!LOGGED_IN) { double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime,^(void){ // Create a login view controller,assign its delegate,and present it LoginViewController *lvc = [[LoginViewController alloc] init]; lvc.delegate = self; [self presentViewController:lvc animated:YES completion:^{ NSLog(@"modal completion finished."); }]; }); } } #pragma mark - LoginViewControllerDelegate - (void)loginViewControllerDidLoginSuccessfully:(LoginViewController *)lvc { NSLog(@"Login VC delegate - Login success!"); [self dismissViewControllerAnimated:YES completion:NULL]; } - (void)loginViewController:(LoginViewController *)lvc didFailWithError:(NSError *)error { // Maybe show an alert... // UIAlertView *alert = ... } - (void)loginViewControllerDidReceivePasswordResetRequest:(LoginViewController *)lvc { // Take the user to safari to reset password maybe NSLog(@"Login VC delegate - password reset!"); } - (void)loginViewControllerDiDReceiveSignupRequest:(LoginViewController *)lvc { // Take the user to safari to open signup form maybe NSLog(@"Login VC delegate - signup requested!"); } - (BOOL)loginViewControllerShouldAllowAnonymousLogin:(LoginViewController *)lvc { return YES; } @end
在某些方面登录可以是一个复杂的互动过程,所以我建议您认真考虑使用委派而不是通知.然而,可能有问题的一件事是,代表必须只是一个对象.如果您需要有多个不同的对象知道登录视图控制器的进度和stae,那么您可能需要使用通知.特别是如果登录过程可以被限制为非常简单,以不需要任何交互的方式超出传递单向消息和数据,则通知可以成为可行的选项.您可以在userInfo属性中的通知中传递任意变量,该属性是您决定在其中填充的NSDictionary.通知可能会影响性能,但我明白,只有当观察员数量在数百人时才会发生.即使这样,它不是最自然的适合我的想法,因为你有父对象(或多或少控制孩子的生命周期)要求第三方对象从子对象的更新.