Ios 将数据从FirstViewController传递到LastViewController

Ios 将数据从FirstViewController传递到LastViewController,ios,objective-c,uiviewcontroller,segue,Ios,Objective C,Uiviewcontroller,Segue,我目前的设计中有四个ViewController,我正在设计一个销售产品的应用程序 FirstViewController获取产品图像,当用户单击“下一步”按钮时,它会将用户带到secondviewcontroller,用户在其中描述产品,然后用户单击“下一步”按钮,将用户带到输入价格和条件的thirdViewcontroller。在lastViewController中有一个post按钮,用于将产品信息发送到服务器。我正在使用POST方法 下面的segue方法不适合我想要的,因为它将first

我目前的设计中有四个ViewController,我正在设计一个销售产品的应用程序

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

下面的segue方法不适合我想要的,因为它将
firstviewcontroller
对象(产品图像)发送到
secondviewcontoller
,然后
secondviewcontroller
还应将产品图像转发到
thirdviewcontoller
,依此类推。我认为这不是一个可行的方法

我想知道从第一页到最后一页收集信息并发送信息的最佳方式是什么。处理这个问题的最佳方式是什么?我在ViewController之间使用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];
    }
}

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


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

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

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


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

请不要使用单件,即使这里的大多数用户都这样告诉你。这将违反法律,原因有几个

相反,只需将对象从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;
    }
}

我创建了一个示例项目:

请注意,所有视图控制器都源自
productawarbeaviewcontroller

@import UIKit;

@class Product;

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

此ViewController知道如何将类
Product
的模型数据传递给
productawarbeaviewcontroller
的其他实例及其子类

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

i、 e:



有趣。非常感谢Philip的快速回答,有什么推荐的教程或示例可以让我实际学习这种方法吗?Philip,我强烈建议不要建议使用app delegate在应用程序中传递数据。这不仅是对应用程序委托的不当使用,而且可能是一个很难摆脱的陷阱,可能会与未来的iOS更改发生冲突。@DanielZhang:我不认为它是不恰当的,正如应用程序委托是应用程序视图和控制器部分的初始化点一样。将其作为模型的主要所有者也具有某种MVC对称性。(尽管如此,我之所以提到它,是因为有些人对“singleton”的反应很糟糕。)至于与iOS变化的冲突,除非你知道一些具体的计划,否则什么都可以说。Phillip,我接受你关于对称性的观点,app delegate就是一个很好的singleton例子。如果我说,不使用app delegate处理全球数据会有很多好处,尤其是经验较少的开发人员。它很容易被滥用,从而导致我提到的陷阱。我不知道iOS即将发生的任何具体变化,但至少这种担心因为没有将代码放在其中而得到缓解。singleton的真正问题是:全局状态->内存混乱,cocoa的内存规则不适用。隐藏的依赖项。很难测试。很难嘲笑。违反OCP。违反DIP。违反LSP。如果使用app delegate作为单例:违反SRP。非常感谢haluzak的快速回答,是否有一个好的教程或示例可以让我实际学习这种方法?@texas你可以在这里了解单例模式:下面是如何在objective-c中实现它:感谢vikingosengundo,在建议的设计原则中,每个viewController对象都需要将产品信息传递给其目标viewController。我说得对吗?你能扩展你的代码示例吗?我正在准备一个示例
#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
#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