在视图控制器之间传递数据

我是 iOS 和 Objective-C 以及整个 MVC 范例的新手,但我坚持以下几点:

我有一个充当数据输入表单的视图,我想给用户选择多个产品的选项。这些产品在另一个带有UITableViewController视图中列出,并且我启用了多个选择。

我的问题是,如何将数据从一个视图传输到另一个视图?我将在数组中的UITableView上保留选择,但是如何将其传递回以前的数据输入表单视图,以便在提交表单时将其与其他数据一起保存到 Core Data?

我到处逛逛,看到有人在应用程序委托中声明了一个数组。我读了一些有关 Singletons 的内容,但不了解它们是什么,并且读了一些有关创建数据模型的知识。

什么是执行此操作的正确方法,我将如何处理?

答案

这个问题在 stackoverflow 上似乎很受欢迎,所以我想我会尝试给出一个更好的答案来帮助像我这样的 iOS 初学者。

我希望这个答案足够清晰,让人们理解,并且我没有错过任何东西。

转发数据

将数据从另一个视图控制器传递到视图控制器。如果要将对象 / 值从一个视图控制器传递到可能要推送到导航堆栈的另一个视图控制器,则可以使用此方法。

对于此示例,我们将有ViewControllerAViewControllerB

要将BOOL值从ViewControllerA传递到ViewControllerB我们需要执行以下操作。

  1. ViewControllerB.hBOOL创建一个属性

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. ViewControllerA您需要向其介绍ViewControllerB因此请使用

    #import "ViewControllerB.h"

    然后在你想加载视图的地方。 didSelectRowAtIndex或某些IBAction ,需要先在ViewControllerB设置该属性,然后再将其推入导航堆栈。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];

    这会将ViewControllerB isSomethingEnabled设置为BOOLYES

使用 Segues 转发数据

如果使用情节提要,则很有可能使用 segues,并且需要此过程将数据转发。这与上面的类似,但是不是在推送视图控制器之前传递数据,而是使用一种称为

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

因此,要将BOOLViewControllerA传递到ViewControllerB我们需要执行以下操作:

  1. ViewControllerB.hBOOL创建一个属性

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. ViewControllerA您需要向其介绍ViewControllerB因此请使用

    #import "ViewControllerB.h"
  3. 在情节ViewControllerB上从ViewControllerAViewControllerB创建一个序列,并为其指定一个标识符,在本示例中,我们将其称为"showDetailSegue"

  4. 接下来,我们需要将方法添加到执行任何 segue 时要调用的ViewControllerA中,因此,我们需要检测调用了哪个 segue,然后执行某些操作。在我们的示例中,我们将检查"showDetailSegue" ,如果执行了此操作,则将BOOL值传递给ViewControllerB

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }

    如果您将视图嵌入导航控制器中,则需要将上面的方法稍微更改为以下方法

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }

    这会将ViewControllerB isSomethingEnabled设置为BOOLYES

传回数据

通过从数据回ViewControllerBViewControllerA需要使用协议和代表 ,后者可以被用作用于回调松散耦合机制。

要做到这一点,我们将ViewControllerA的委托ViewControllerB 。这使ViewControllerB可以将消息发送回ViewControllerA从而使我们能够将数据发送回去。

对于ViewControllerA是的委托ViewControllerB它必须符合ViewControllerB我们有指定的协议。这告诉ViewControllerA它必须实现哪些方法。

  1. ViewControllerB.h ,在#import下方,但在@interface上方,指定协议。

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
  2. 接下来仍然在ViewControllerB.h您需要设置一个delegate属性并在ViewControllerB.m合成

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. ViewControllerB ,当我们弹出视图控制器时,我们在delegate上调用一条消息。

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. 这就是ViewControllerB 。现在在ViewControllerA.h ,告诉ViewControllerA导入ViewControllerB并遵守其协议。

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. ViewControllerA.m ,从我们的协议中实现以下方法

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
  6. 在将viewControllerB推到导航堆栈之前,我们需要告诉ViewControllerB ViewControllerA是它的委托,否则我们将得到一个错误。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];

参考文献

  1. View Controller 编程指南》中的使用委派与其他 View Controller 通信
  2. 代表图案

NSNotification 中心这是传递数据的另一种方法。

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

将数据从一个类传递回另一个类 (一个类可以是任何控制器,网络 / 会话管理器,UIView 子类或任何其他类)

块是匿名函数。

本示例将数据从控制器 B传递到控制器 A

定义一个块

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

在需要值的地方添加块处理程序(侦听器) (例如,您需要在 ControllerA 中的 API 响应或在 A 上需要 ContorllerB 数据)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

转到控制器 B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

火块

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

块的另一个工作示例

迅速

此处和有关 StackOverflow 的解释不计其数,但是如果您是初学者,只是想尝试一些基本的知识,请尝试观看此 YouTube 教程(这是帮助我最终了解如何做的)。

将数据转发到下一个 View Controller

以下是基于视频的示例。想法是将字符串从 “第一视图控制器” 中的文本字段传递到 “第二视图控制器” 中的标签。

在此处输入图片说明

在 “界面生成器” 中创建情节提要板布局。要进行设置,只需按住 Control键单击该按钮,然后拖动到 Second View Controller。

第一视图控制器

First View Controller 的代码是

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

第二视图控制器

第二视图控制器的代码是

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

别忘了

  • 连接UITextFieldUILabel的出口。
  • 将第一个和第二个 View Controller 设置为 IB 中的相应 Swift 文件。

将数据传回上一个 View Controller

要将数据从第二个视图控制器传递回第一个视图控制器,请使用协议和委托 。该视频非常清晰地介绍了该过程:

以下是基于视频的示例(进行了一些修改)。

在此处输入图片说明

在 “界面生成器” 中创建情节提要板布局。同样,要进行设置,只需将Control从按钮拖动到 Second View Controller。将 segue 标识符设置为showSecondViewController 。另外,不要忘记使用以下代码中的名称来连接插座和操作。

第一视图控制器

First View Controller 的代码是

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

请注意我们自定义的DataEnteredDelegate协议的使用。

Second View 控制器和协议

第二个视图控制器的代码是

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: AnyObject {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

请注意,该protocol在 View Controller 类之外。

而已。现在运行该应用程序,您应该能够将数据从第二个视图控制器发送回第一个。

MVC 中的 M 用于 “模型”,在 MVC 范例中,模型类的作用是管理程序数据。模型与视图相反 - 视图知道如何显示数据,但对数据处理一无所知,而模型却不知道如何处理数据,而对如何显示数据一无所知。模型可能很复杂,但不必一定如此 - 应用程序的模型可能像字符串或字典的数组一样简单。

控制器的作用是在视图和模型之间进行中介。因此,他们需要引用一个或多个视图对象和一个或多个模型对象。假设您的模型是一个字典数组,每个字典代表表中的一行。应用程序的根视图将显示该表,它可能负责从文件加载阵列。当用户决定向表中添加新行时,他们点击某个按钮,您的控制器将创建一个新的(可变)字典并将其添加到数组中。为了填写该行,控制器创建了一个详细视图控制器,并为其提供了新的字典。细节视图控制器将填充字典并返回。字典已经是模型的一部分,因此不需要进行其他任何操作。

在 iOS 中,可以通过多种方式将数据接收到不同的类。例如 -

  1. 分配另一个类后直接初始化。
  2. 委托 - 用于将数据传回
  3. 通知 - 一次将数据广播到多个类别
  4. 保存在NSUserDefaults - 以后访问
  5. 单身人士班
  6. 数据库和其他存储机制,例如 plist 等。

但是对于将值传递给在当前类中完成分配的另一个类的简单方案,最常见和首选的方法是分配后直接设置值。这样做如下:

我们可以使用两个控制器来理解它-Controller1 和 Controller2

假设在 Controller1 类中要创建 Controller2 对象,并通过传递的 String 值来推送它。可以这样做:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

在 Controller2 类的实现中,此功能为 -

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

您还可以通过类似的方式直接设置 Controller2 类的属性:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

要传递多个值,可以使用多个参数,例如:

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date];

或者,如果您需要传递与通用功能相关的三个以上参数,则可以将值存储到 Model 类中,然后将该 modelObject 传递给下一个类

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

简而言之,如果您想 -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

希望这可以帮助

经过更多研究后,似乎 “协议和委托” 是正确的 / Apple 偏爱的方式。

我最终使用了这个例子

在视图控制器和其他对象之间共享数据 @ iPhone Dev SDK

工作正常,并允许我在视图之间来回传递字符串和数组。

感谢你的帮助

我发现带有传递块的最简单,最优雅的版本。让我们将等待返回数据的视图控制器命名为 “A”,将等待返回数据的视图控制器命名为 “B”。在此示例中,我们希望获得 2 个值:第一个是 Type1,第二个是 Type2。

假设我们使用 Storyboard,则第一个控制器设置回调块,例如在进行序列准备期间:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

和 “B” 视图控制器应声明回调属性 BViewController.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

在具有所需值以返回回调后,应在实现文件 BViewController.m 中调用以下方法:

if (self.callback)
    self.callback(value1, value2);

有一点要记住的是,经常使用块需要强有力的管理和__weak 引用类似解释这里

给出的许多答案中都有一些很好的信息,但没有一个能够完全解决问题。

该问题询问有关在视图控制器之间传递信息的问题。给出的特定示例询问有关在视图之间传递信息的问题,但是鉴于 iOS 的自我声明的新颖性,原始张贴者可能意味着在 ViewController 之间,而不是视图之间(不涉及 ViewController)。似乎所有答案都集中在两个视图控制器上,但是如果应用程序演变为需要在信息交换中包含两个以上的视图控制器,该怎么办?

原始海报还询问了Singletons以及AppDelegate的用法。这些问题需要回答。

为了帮助其他人,这个问题想要一个完整的答案,我将尝试提供它。

应用场景

与其进行高度假设性的抽象讨论,不如将其牢记在心。为了帮助定义两个视图控制器的情况和一个多于两个视图控制器的情况,我将定义两个具体的应用场景。

方案 1:最多需要两个视图控制器共享信息。参见图一。

原始问题图

应用程序中有两个视图控制器。有一个 ViewControllerA(数据输入表单)和一个 View Controller B(产品列表)。产品列表中选择的项目必须与数据输入表单中文本框中显示的项目匹配。在这种情况下,ViewControllerA 和 ViewControllerB 必须彼此直接通信,并且没有其他视图控制器。

方案二两个以上的视图控制器需要共享相同的信息。见图二。

房屋库存应用图

该应用程序中有四个视图控制器。它是用于管理房屋库存的基于选项卡的应用程序。三个视图控制器显示相同数据的不同过滤视图:

  • ViewControllerA - 奢侈品
  • ViewControllerB - 非保险项目
  • ViewControllerC - 整个房屋库存
  • ViewControllerD - 添加新项目表单

每当创建或编辑单个项目时,它还必须与其他视图控制器同步。例如,如果我们在 ViewControllerD 中添加一条船,但尚未投保,则该船必须在用户转到 ViewControllerA(豪华物品)和 ViewControllerC(整个房屋库存)时出现,但在用户转到 ViewControllerB(非保险项目)。我们不仅需要关注添加新项,还需要删除项(可以从四个视图控制器中的任何一个中删除),或者编辑现有项(可以从 “添加新项表单” 中允许,重新使用相同项)进行编辑)。

由于所有视图控制器确实需要共享相同的数据,因此所有四个视图控制器都需要保持同步,因此,只要任何一个视图控制器更改基础数据,就需要与所有其他视图控制器进行某种形式的通信。很明显,在这种情况下,我们不希望每个视图控制器都直接与彼此通信。如果不太明显,请考虑是否有 20 个不同的视图控制器(而不是 4 个)。每当一个视图控制器进行更改时,通知其他 19 个视图控制器将是多么困难且容易出错?

解决方案:代表和观察员模式以及单例

在方案一中,我们有几种可行的解决方案,其他答案也已给出

  • 塞格斯
  • 代表
  • 直接在视图控制器上设置属性
  • NSUserDefaults(实际上是一个糟糕的选择)

在方案二中,我们还有其他可行的解决方案:

  • 观察者模式
  • 单身人士

单例是类的实例,该实例是其生命周期中存在的唯一实例。单例的名称是因为它是单个实例。通常,使用单例的开发人员具有访问它们的特殊类方法。

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

现在我们了解了单例是什么,让我们讨论单例如何适应观察者模式。观察者模式用于一个对象响应另一对象的更改。在第二种情况下,我们有四个不同的视图控制器,他们都想知道基础数据的更改。 “基础数据” 应属于单个实例,单个实例。 “了解更改” 是通过观察对单例所做的更改来完成的。

家庭库存应用程序将具有一个类的单个实例,该类旨在管理库存项目列表。经理将管理一系列家居用品。以下是数据管理器的类定义:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

当房屋库存项目的收集发生更改时,需要使视图控制器知道此更改。上面的类定义并不明显如何实现。我们需要遵循观察者模式。视图控制器必须正式遵守 sharedManager。有两种观察另一个对象的方法:

  • 键值观察(KVO)
  • NSNotificationCenter。

在方案二中,我们没有使用 KVO 可以观察到的 HouseholdInventoryManager 的单个属性。因为我们没有一个易于观察的属性,所以在这种情况下,观察者模式必须使用 NSNotificationCenter 来实现。四个视图控制器中的每一个都将订阅通知,并且 sharedManager 将在适当时将通知发送到通知中心。库存管理器不需要了解有关视图控制器或任何其他类的实例的任何知识,这些类可能对知道库存项目的集合何时更改有兴趣。 NSNotificationCenter 负责这些实现细节。视图控制器仅订阅通知,而数据管理器仅发布通知。

许多初学者都利用了这样一个事实,那就是在应用程序的生命周期中始终只有一个应用程序委托 ,该委托可以全局访问。入门程序员使用此事实将对象和功能填充到 appDelegate 中,以方便从应用程序中的任何其他位置访问。仅仅因为 AppDelegate 是一个单例并不意味着它应该替换所有其他单例。这是一种糟糕的做法,因为它将过多的负担放在一个类上,破坏了良好的面向对象的做法。每个类都应具有明确的角色,且通常仅通过类名即可轻松解释。

每当您的应用程序代理开始变得肿时,就开始将功能删除为单例。例如,不应将 Core Data Stack 保留在 AppDelegate 中,而应将其放在自己的类 coreDataManager 类中。

参考文献

OP 没有提到视图控制器,但是有很多答案,我想了解一下 LLVM 的一些新功能,以便在要将数据从一个视图控制器传递到另一个视图控制器,然后再将其传递给其他人时,使此操作变得更加容易得到一些结果。

故事板脚本,ARC 和 LLVM 块使这比以往任何时候都容易。上面的一些答案已经提到了故事板和 segues,但仍然依赖于授权。定义委托当然可以,但是有些人可能会发现更容易传递指针或代码块。

使用 UINavigators 和 segues,可以使用简单的方法将信息传递到从属控制器,然后将信息取回。 ARC 使传递指向从 NSObjects 派生的事物的指针变得简单,因此,如果您希望子服务器控制器为您添加 / 更改 / 修改某些数据,请将其传递给可变实例的指针。块使传递动作变得容易,因此,如果您希望从属控制器在更高级别的控制器上调用动作,则将其传递给块。您定义该块以接受对您有意义的任意数量的参数。如果更适合,您还可以设计 API 以使用多个块。

这是 segue 胶的两个简单例子。第一个很简单,显示了一个传递给输入的参数,第二个传递给输出。

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

第二个示例显示传递第二个参数的回调块。我喜欢使用块,因为它使相关细节在源(更高级的源)中并排在一起。

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}

将数据从 ViewController 2(目标)传递回 viewController 1(源)是更有趣的事情。假设您使用 StoryBoard,这些就是我发现的所有方式:

  • 代表
  • 通知
  • 用户默认值
  • 辛格尔顿

这些已经在这里讨论过了。

我发现还有更多方法:

- 使用块回调:

在 VC1 的prepareForSegue方法中使用它

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

- 使用情节提要板展开(退出)

在 VC 1 中使用 UIStoryboardSegue 参数实现一种方法,如下所示:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

在故事板中,将 “返回” 按钮挂接到 vc 的绿色 “退出” 按钮(展开)。现在您有了一个 “返回” 的选项,因此您可以在 VC2 的 prepareForSegue 中使用 destinationViewController 属性,并在返回之前更改 VC1 的任何属性。

  • 使用情节提要板 Undwind(退出)的另一种选择 - 您可以使用在 VC1 中编写的方法

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    }

    在 VC1 的 prepareForSegue 中,您可以更改要共享的任何属性。

在这两个展开选项中,您可以设置按钮的 tag 属性,并在 prepareForSegue 中进行检查。

希望我在讨论中添加了一些内容。

:) 干杯。

有多种共享数据的方法。

  1. 您始终可以使用NSUserDefaults共享数据。根据您选择的键设置要共享的值,并从下一个视图控制器中与该键关联的NSUserDefault中获取值。

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
  2. 您可以只在viewcontrollerA创建一个属性。在viewcontrollerB创建一个viewcontrollerA对象,并将所需的值分配给该属性。

  3. 您也可以为此创建自定义委托。