将数据从Child Modal VC传递到父视图控制器的最佳方法? [英] Best way to pass data from Child Modal VC to the Parent View Controller?

查看:75
本文介绍了将数据从Child Modal VC传递到父视图控制器的最佳方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将数据从子模式视图传递到父视图控制器的最佳方法是什么?

What is the best way to pass data from a child modal view to the parent view controller?

我的iPad应用程序上有一个儿童模态登录屏幕想要将用户信息传递给父拆分视图控制器。

I have a Child Modal Login Screen on my iPad app that I want to pass back user information to the parent Split View Controller.

我正在考虑使用NSNotification,但我不确定这是否是最简单/最有效的方式将数据传回给父母。

I am thinking of using NSNotification, but I am not sure if this is the easiest/most efficient way to pass data back to the parent.

谢谢!
Alan

Thanks! Alan

推荐答案

我建议,正如iPatel所做的那样,使用代表团来解决您的问题。父视图控制器和登录视图控制器之间的关系使该模式适当。当一个对象创建另一个对象以履行特定职责时,应该将委托视为使创建的对象与创建者通信的一种方式。选择委派的一个特别令人信服的理由是,如果要完成的任务可能具有多个步骤,这些步骤需要对象之间的高级别交互。您可以查看 NSURLConnectionDelegate 协议作为对此的说明。连接到URL是一项复杂的任务,涉及诸如处理响应,满足认证质询,保存下载数据和处理错误等阶段,连接和委托在连接的生命周期内处理这些。

I would suggest, as iPatel did, to use delegation to solve your problem. The relationship between the parent view controller and the login view controller makes this pattern appropriate. When one object creates another in order to fulfill a specific responsibility, one should consider delegation as a way to have the created object communicate with the creator. A particularly compelling reason to choose delegation would be if the task to be accomplished potentially has multiple steps that require a high level of interaction between objects. You can look at the NSURLConnectionDelegate protocol as an illustration of this. Connecting to a URL is a complex task, involving stages such as processing responses, meeting authentication challenges, saving downloaded data, and handling errors, the connection and the delegate handle this together over the lifetime of the connection.

您可能已经注意到,Objective-C协议用于实现委派而不将创建的对象(在本例中为登录视图控制器)紧密耦合到创建它的对象(父视图)控制器)。然后,登录视图控制器可以与任何可以接收其协议中定义的消息的对象进行交互,而不是依赖于任何特定的类实现。明天,如果您收到允许任何视图控制器显示登录视图的要求,则登录视图控制器不需要更改。您的其他视图控制器可以实现其委托协议,创建和显示登录视图,并将自己分配为委托,而登录视图控制器不知道它们的存在。

As you've probably noticed, in Objective-C protocols are used to achieve delegation without tightly coupling the created object (in this case your login view controller) to the object that created it (the parent view controller). The login view controller can then interact with any object that can receive the messages defined in its protocol, rather than rely on any particular class implementation. Tomorrow, if you receive a requirement to allow any view controller to show the login view, the login view controller wouldn't need to change. Your other view controllers can implement its delegate protocol, create and present the login view, and assign themselves as delegates without the login view controller ever knowing of their existence.

一些委托您将在Stack Overflow上找到的示例可能非常混乱,并且非常类似于内置框架中的内容。必须仔细选择协议的名称和接口,以及分配给每个对象的职责,以便最大化代码重用并实现代码的目标。

Some delegation examples you'll find on Stack Overflow may be very confusing and very un-like what's found in the built-in frameworks. One must pick the names and interfaces of the protocols carefully, as well as the responsibilities assigned to each object, so that code reuse is maximized and the objective of the code is achieved.

您应首先查看内置框架中的许多委托协议,以了解在代码中表达时的关系。这是另一个小例子,基于您的登录用例。我希望您会发现代表团的目的很明确,所涉对象的角色和责任是明确的,并通过代码中的名称来表达。

You should first take a look at the many delegate protocols within the built-in frameworks for an idea of what the relationship looks like when expressed in code. Here is another small example, based on your login use case. I hope you will find that the purpose of the delegation is clear and that the roles and responsibilities of the objects involved are clear and expressed through their names within the code.

First ,让我们看一下LoginViewController的委托协议:

First, let's look at the LoginViewController's delegate protocol:

#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

登录控制器可以将多个事件传达给它委托,以及向其代表询问用于定制其行为的信息。它将事件中的事件作为其对用户操作的响应的一部分传递给代理:

The login controller can communicate a number of events to its delegate, as well as ask its delegate for information used to customize its behavior. It communicates events to the delegate in its implementation as part of its response to user actions:

#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

主视图控制器实例化和提供一个登录视图控制器,并处理其委托消息:

The main view controller instantiates and presents a login view controller, and handles its delegate messages:

#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

登录可能很复杂,在某些方面的互动过程,所以我建议你认真考虑使用委托而不是通知。然而,可能有问题的一件事是代表必然只是一个对象。如果您需要知道登录视图控制器的进度和stae的多个不同对象,则可能需要使用通知。特别是如果登录过程可以被限制为非常简单,除了传递单向消息和数据之外不需要任何交互,那么通知可以成为可行的选择。您可以在 userInfo 属性中的通知中传递任意变量,该属性是 NSDictionary ,无论您决定填写什么内容它。通知可以影响性能,但据我所知,现在只有当观察者数量达到数百时才会发生。即使如此,它仍然不是最自然的,因为你有父对象(或多或少控制孩子的生命周期)向第三方对象请求子对象的更新。

Logging in can be a complex, interactive process in some ways, so I do recommend you seriously consider using delegation instead of notifications. However, one thing that may be problematic is that delegates are necessarily only a single object. If you need to have multiple, disparate objects know about the login view controller's progress and stae, then you may need to use notifications. Especially if the login process can be constrained to be very simple, in a way that does not require any interaction beyond passing one-way messages and data, then notifications can become a viable option. You can pass arbitrary variables in a notification back inside the userInfo property which is an NSDictionary of whatever you decide to stuff in it. Notifications can impact performance but I understand that only happens nowadays when observers number in the hundreds. Even still, it is not the most natural fit in my mind, as you have the parent object (that more or less controls the lifetime of the child) asking a third party object for updates from the child object.

这篇关于将数据从Child Modal VC传递到父视图控制器的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆