将数据从 FirstViewController 传递到 LastViewController

Posted

技术标签:

【中文标题】将数据从 FirstViewController 传递到 LastViewController【英文标题】:Passing data from the FirstViewController to the LastViewController 【发布时间】:2015-10-06 21:18:32 【问题描述】:

我目前的设计中有四个视图控制器,我正在设计一个应用程序来销售产品。

FirstViewController 获取产品图片,当用户点击下一个按钮时,它会将用户带到用户描述产品的secondviewcontroller,然后用户点击下一个按钮,将用户带到价格和条件的thirdViewcontroller被输入。在lastviewcontolller 中有一个发布按钮,用于将产品信息发送到服务器。我正在使用POST 方法。

以下segue方法不适合我想要的,因为它将firstviewcontroller对象(产品图像)发送到secondviewcontoller,然后secondviewcontroller也应该将产品图像转发到thirdviewcontoller和很快。我不认为这是一种可行的方法。

我想知道从第一页到最后一页收集信息并发送的最佳方式是什么。处理该问题的最佳方法是什么?我在视图控制器之间使用 segue。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"isSecond"])
    
        // Get reference to the destination view controller
        SecondViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyProductImage:productImage];
    

【问题讨论】:

【参考方案1】:

不要使用单例,即使这里的大多数用户都这样告诉你。出于多种原因,它会违反SOLID-Principles。

而只是将对象从 ViewController 传递给 ViewController。

如果所有 ViewController 都期望相同的模型类,您可以创建一个具有模型属性的公共基类。

可以有这个方法

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if ([segue.destinationViewControler isKindOfClass:[ProductAwareBaseViewController class]])
    
        ProductAwareBaseViewController *vc = (ProductAwareBaseViewController *)segue.destinationViewControler;
        vc.product = self.product;
    


我创建了一个示例项目:https://github.com/vikingosegundo/ProductWizard

注意,所有视图控制器都派生自ProductAwareBaseViewController

@import UIKit;

@class Product;

@interface ProductAwareBaseViewController : UIViewController
@property (nonatomic, strong) Product *product;
@end

#import "ProductAwareBaseViewController.h"
#import "Product.h"

@interface ProductAwareBaseViewController ()

@end

@implementation ProductAwareBaseViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if ([segue.destinationViewController isKindOfClass:[ProductAwareBaseViewController class]]) 
        ProductAwareBaseViewController *vc = (ProductAwareBaseViewController *)segue.destinationViewController;
        vc.product = self.product;
    

@end

这个 ViewController 知道如何将 Product 类的模型数据传递给 ProductAwareBaseViewController 的其他实例及其子类。

所有其他视图控制器不处理传递数据,只是将数据的每个部分(名称、描述、价格)添加到模型并显示它。

即:

#import "EditNameProductViewController.h"
#import "Product.h"

@interface EditNameProductViewController () 
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@end

@implementation EditNameProductViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    self.product = [[Product alloc] init]; 


- (IBAction)continueTapped:(id)sender 
    self.product.productName = self.nameField.text; 


@end

#import "EditDescriptionProductViewController.h"
#import "Product.h"

@interface EditDescriptionProductViewController ()
@property (weak, nonatomic) IBOutlet UITextField *descriptionField;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@end

@implementation EditDescriptionProductViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    self.nameLabel.text = self.product.productName;


- (IBAction)continueTapped:(id)sender 
    self.product.productDescription = self.descriptionField.text;


@end

【讨论】:

感谢 vikingosengundo,在您提出的设计原则中,每个 viewController 对象都需要将产品信息传递给其目标 viewcontroller。我对吗?您能否扩展您的代码示例? 我正在准备一个例子【参考方案2】:

创建一个对象作为应用程序的数据模型。它可以是单例,也可以是可从已知位置获得的普通对象……例如由应用程序委托拥有。

当您有新信息时更新您的模型,并在需要显示某些内容时从模型中读取。对于简单的事情,使用prepareForSegue: 和链接控制器可能是可以接受的,但它确实不能很好地扩展。

【讨论】:

有趣。非常感谢 Philip 的快速回答,是否有任何推荐的教程或示例可以让我实际学习这种方法? Phillip,我强烈建议不要使用应用委托在应用内传递数据。这不仅是对应用程序委托的不当使用,而且可能是一个难以摆脱的陷阱,并且可能与未来的 ios 更改发生冲突。 @DanielZhang:我不认为它比应用程序委托作为应用程序的视图和控制器部分的初始化点更不合适。让它作为模型的主要所有者也具有一定的 MVC 对称性。 (话虽这么说,我只提它是因为有些人对“单例”反应很差。)至于与iOS变化的冲突,除非你知道一些具体的计划,否则绝对可以说。 Phillip,我接受您关于对称性的观点,并且应用程序委托是单例的一个很好的例子。如果不使用应用程序代理来获取全局数据,尤其是经验不足的开发人员,那么对我来说会更有建设性。它很容易被滥用,从而导致我提到的陷阱。我不知道即将发生的任何具体 iOS 更改,但至少通过不将代码放在其中,这种担忧得到了缓解。 单例的真正问题:全局状态 -> 内存混乱,可可的内存规则不适用。隐藏的依赖。很难测试。很难嘲笑。违反 OCP。违反 DIP。违反 LSP。如果将应用程序委托用作单例:违反 SRP。【参考方案3】:

这样做的一种方法是在第一个视图控制器中创建一个可变字典(或带有变量的自定义对象)。然后,您将从第一个视图控制器传递对可变字典/对象的第二/第三/第四视图控制器的弱引用。每个视图控制器都可以为字典/对象设置数据,最后一个可以处理信息。

另一种方法是创建一个简单的单例类,其中包含要存储的变量。第一个视图控制器将重置单例变量。然后让每个视图控制器访问单例并将它们的值存储在那里,最后一个视图控制器将处理来自单例的值。

这取决于您收集了多少数据以及您个人喜欢什么。

【讨论】:

非常感谢 haluzak 的快速回答,是否有好的教程或示例可以让我实际学习这种方法? @texas 你可以在这里了解单例模式:en.wikipedia.org/wiki/Singleton_pattern,这里是如何在 Objective-c 中实现它:galloway.me.uk/tutorials/singleton-classes

以上是关于将数据从 FirstViewController 传递到 LastViewController的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 panGesture 从 firstViewController 的顶部移动 secondViewController?

从 Thirdviewcontroller 到 FirstViewcontroller

当从其父视图中删除第二个 ViewController 时,FirstViewController 不起作用

将 indexpath 值传递给 FirstViewController

我可以将 SecondViewController 上的图像传递给 FirstViewController 吗?

如何将数据从模态 ViewController 传输到父 ViewController?