将数据从Child Modal VC传递到父视图控制器的最佳方法是什么?
将数据从子模式视图传递给父视图控制器的最佳方式是什么?
我在我的iPad应用程序上有一个儿童模式login屏幕,我想将用户信息传回给父视图控制器。
我想使用NSNotification,但我不知道这是否是最简单/最有效的方式将数据传回父。
谢谢! 艾伦
我会build议, 像iPatel一样 ,使用代表团来解决你的问题。 父视图控制器和login视图控制器之间的关系使此模式适当。 当一个对象为了履行特定的责任而创build另一个对象时,应该把委托视为让创build的对象与创build者通信的一种方式。 select委托的一个特别有说服力的理由是,如果要完成的任务潜在地具有需要在对象之间高度交互的多个步骤。 你可以看一下NSURLConnectionDelegate
协议 。 连接到URL是一项复杂的任务,涉及处理响应,遇到身份validation挑战,保存下载的数据和处理错误等阶段,连接和委托在连接的整个生命周期中一起处理。
正如你可能已经注意到的那样,Objective-C协议用于实现委托,而不是将创build的对象(在这种情况下是你的login视图控制器)与创build对象(父视图控制器)紧密耦合。 然后,login视图控制器可以与任何可以接收其协议中定义的消息的对象进行交互,而不依赖于任何特定的类实现。 明天,如果您收到要求允许任何视图控制器显示login视图,login视图控制器将不需要更改。 您的其他视图控制器可以实现其委托协议,创build和呈现login视图,并将自己指定为委托,而无需login视图控制器知道它们的存在。
你可以在堆栈溢出中find一些代表性的例子,可能会非常混乱,而且非常不像在内置框架中发现的那样。 必须仔细挑选协议的名称和接口,以及分配给每个对象的职责,以使代码重用最大化,实现代码的目标。
您应该先看看内置框架中的许多委托协议,以了解在代码中expression关系的样子。 这是另一个小例子,基于你的login用例。 我希望你们会发现,代表团的目的是明确的,所涉及的对象的angular色和责任是明确的,并通过它们的名字在代码中expression。
首先,让我们来看看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
login控制器可以将许多事件传递给它的委托,也可以向委托人询问用于定制其行为的信息。 它将实现中的事件作为响应用户操作的一部分传达给委托人:
#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
主视图控制器实例化并呈现一个login视图控制器,并处理其委托消息:
#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, dispatch_get_main_queue(), ^(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
在某些方面login可能是一个复杂的交互式过程,所以我build议您认真考虑使用委派而不是通知。 但是,有一点可能是有问题的,即代表只能是一个单一的对象。 如果您需要有多个不同的对象了解login视图控制器的进度和状态,则可能需要使用通知。 特别是如果login过程可以被限制为非常简单,那么除了传递单向消息和数据之外不需要任何交互,通知可以成为可行的select。 你可以在userInfo
属性里传递一个通知中的任意variables,这个属性是你决定填充的NSDictionary
。 通知可以影响性能,但是我知道现在只有当观察者人数达到几百时才会发生。 即使如此,它并不是最合适的,因为你有父对象(或多或less地控制了子对象的生命周期)向第三方对象请求子对象的更新。
你可以通过使用协议得到它,这是最好的方法。
我会给你如何创build一个协议的基本思想
另外,阅读这个问题: 如何在Objective-C中创build委托?
下面的代码给你的协议的基本思想,在这里下面的代码中,你可以从MasterViewController
button标题DetailViewController
。
#DetailViewController.h #import <UIKit/UIKit.h> @protocol MasterDelegate <NSObject> -(void) getButtonTitile:(NSString *)btnTitle; @end @interface DetailViewController : MasterViewController @property (nonatomic, assign) id<MasterDelegate> customDelegate; #DetailViewController.m if([self.customDelegate respondsToSelector:@selector(getButtonTitile:)]) { [self.customDelegate getButtonTitile:button.currentTitle]; } #MasterViewController.m create obj of DetailViewController DetailViewController *obj = [[DetailViewController alloc] init]; obj.customDelegate = self; [self.navigationController pushViewController:reportTypeVC animated:YES]; and add delegate method in MasterViewController.m for get button title. #pragma mark - #pragma mark - Custom Delegate Method -(void) getButtonTitile:(NSString *)btnTitle; { NSLog(@"%@", btnTitle); }