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

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

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

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

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

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

标签:ios,objective-c,swift,model-view-controller,uiviewcontroller

回答1:

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

我希望这个答案足够清楚,以使人们能够理解,并且我没有错过任何事情。

转发数据

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

在此示例中,我们将有ViewControllerAViewControllerB

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

  1. ViewControllerB.h中为BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. 创建一个属性
  3. ViewControllerA中,您需要告诉它有关ViewControllerB的信息,因此请使用

    #import "ViewControllerB.h"
    

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

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

使用Segues转发数据

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

的方法
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

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

  1. ViewControllerB.h中为BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. 创建一个属性
  3. ViewControllerA中,您需要向其介绍ViewControllerB,因此请使用

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

  5. 接下来,我们需要将方法添加到执行任何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;
        }
    }
    

    这将设置isSomethingEnabled ViewControllerB中更改为BOOLYES

传回数据

要将数据从ViewControllerB传递回ViewControllerA,您需要使用协议和代理,后者可用作回调的松散耦合机制。

为此,我们将使ViewControllerA成为ViewControllerB的委托。这样,ViewControllerB可以将消息发送回ViewControllerA,使我们能够将数据发送回去。

要使ViewControllerA成为ViewControllerB的委托,它必须符合我们必须指定的ViewControllerB协议。这告诉ViewControllerA它必须实现哪些方法。

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

    -(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;
        }
    }
    
  2. 下一步仍然在ViewControllerB.h中,您需要设置delegate属性并在ViewControllerB.m

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  3. ViewControllerB中,当我们弹出视图控制器时,在delegate上调用一条消息。

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  4. ViewControllerB就是这样。现在,在ViewControllerA.h中,告诉ViewControllerA导入ViewControllerB并遵守其协议。

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
    < / li>
  5. ViewControllerA.m中通过我们的协议实现以下方法

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  6. 在将viewControllerB推入导航堆栈之前,我们需要告诉ViewControllerBViewControllerA是其委托,否则我们将得到一个错误。

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    

参考文献

  1. View Controller编程指南
  2. 中的使用委派与其他View Controller进行通信
  3. 委托模式 < / li>

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

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

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

块是匿名函数。

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

定义一个区块

// 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];

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

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

转到控制器B

// in ContollerA.m

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

障碍物

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

另一个块的工作示例

回答2:

迅速

此处和StackOverflow周围都有大量的解释,但是,如果您是初学者,只是想尝试一些基本的知识,请尝试观看此YouTube教程(这是帮助我最终了解如何做的事情)。 / p>

将数据转发到下一个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!
    }

}

第二视图控制器

第二个View Controller的代码是

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协议的使用。

第二视图控制器和协议

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

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)
    }
}

请注意,协议在View Controller类之外。

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

回答3:

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

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

回答4:

有多种方法可以将数据接收到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.

希望这会有所帮助

回答5:

经过更多研究,似乎协议和代表是正确的/ Apple偏爱的方式。

我最终使用了这个示例

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

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

感谢您的所有帮助

回答6:

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

假设我们使用故事板,则第一个控制器设置回调块,例如在准备segue期间:

- (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的引用,如解释的此处

回答7:

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

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

原始海报发布者还询问了单曲 AppDelegate 的使用。这些问题需要回答。

为帮助其他人在查看此问题时想要一个完整的答案,我将尝试提供它。

应用场景

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

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

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

第二种情况:两个以上的视图控制器需要共享相同的信息。参见图二。

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

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

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

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

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

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

  • segues
  • 代理人
  • 直接在视图控制器上设置属性
  • 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负责这些实现细节。 View Controller只需订阅通知,而数据管理器只需发布通知。

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

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

参考

回答8:

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

Storyboard Segue,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];
    }];
}

回答9:

更有趣的是将数据从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的绿色"退出"按钮(展开)。现在您有了一个"返回"的segue,因此您可以在VC2的prepareForSegue中使用destinationViewController属性,并在返回之前更改VC1的任何属性。

  • 使用情节提要板撤消(退出)的另一个选项-您可以使用在VC1中编写的方法

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

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

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

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

:)干杯。

回答10:

有多种共享数据的方法。

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

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

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

回答11:

如果要将数据从一个控制器传递到另一个控制器,请尝试以下代码

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }

回答12:

我一直在寻找这种解决方案,Atlast我找到了。首先,在您的SecondViewController.h文件中声明所有对象,例如

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

现在在您的实现文件中为此类对象分配内存

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

现在,您已经为Array和对象分配了内存。现在您可以在推送此ViewController

之前填充该内存

转到您的SecondViewController.h并编写两个方法

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

在实现文件中,您可以实现功能

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

期望您的CustomObject必须具有setter函数。

现在您的基本工作已经完成。转到要推送SecondViewController的地方,然后执行以下操作

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

注意拼写错误。

回答13:

这是一个非常古老的答案,这是反模式,请使用委托。不要使用这种方法!!!

1。。在第二个View Controller中创建第一个View Controller的实例,并将其属性设置为@property(非原子,分配)

2。。分配此视图控制器的SecondviewController实例。

2。。完成选择操作后,将阵列复制到第一个View Controller,当您卸载SecondView时,FirstView将保存阵列数据。

希望有帮助。

回答14:

这不是这样做的方法,您应该使用委托,我假设我们有两个视图控制器ViewController1和ViewController2,并且此检查项位于第一个中,当其状态更改时,您想要在ViewController2,要以正确的方式实现该目标,您应该执行以下操作:

将新文件添加到您的项目(Objective-C协议)文件->新建,现在将其命名为ViewController1Delegate或您想要的任何名称,并在@interface和@end指令之间编写这些文件

@optional

- (void)checkStateDidChange:(BOOL)checked;

现在转到ViewController2.h并添加

#import "ViewController1Delegate.h"

然后将其定义更改为

@interface ViewController2: UIViewController<ViewController1Delegate>

现在转到ViewController2.m并在实现内部添加:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

现在转到ViewController1.h并添加以下属性:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

现在,如果在某些事件之后在ViewController2中创建ViewController1,则应该使用NIB文件以这种方式进行操作:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

现在您已经准备就绪,每当您在ViewController1中检测到支票更改事件时,只需执行以下操作

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

请告诉我,如果我不能正确理解您的问题,还有什么不清楚的地方。

回答15:

如果您想将数据从一个发送到另一个viewController,请采用以下方法:

假设我们有viewControllers:viewControllerA和viewControllerB

现在在viewControllerB.h中

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

在viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

在viewControllerA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

因此,这是无需设置任何委托即可将数据从viewControllerA传递到viewControllerB的方法。 ;)

回答16:

我知道这是一个受挫的话题,但是对于那些希望通过SWIFT倾斜来回答这个问题并且想要举一个简单的例子的人,如果您使用segue来解决问题,这里是我传递数据的首选方法。< / p>

与上面类似,但没有按钮,标签等。只是简单地将数据从一个视图传递到另一个视图。

设置情节提要

分为三个部分。

  1. 发件人
  2. Segue
  3. 接收者

这是一个非常简单的视图布局,它们之间有缝线。



这是发件人的设置



这是接收机的设置。



最后,是segue的设置。



视图控制器

我们一直保持这种简单,因此没有按钮,没有动作,我们只是在应用程序加载时将数据从发送方移动到接收方,然后将传输的值输出到控制台。

此页面采用初始加载的值并将其传递。

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"

    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

此页面仅在加载变量时将其值发送到控制台。至此,我们最喜欢的电影应该在该变量中。

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }   
}

如果您要使用segue并且您的页面不在导航控制器下,这就是解决该问题的方法。

一旦运行,它将自动切换到接收者视图,并将值从发送者传递到接收者,并在控制台中显示该值。

回答17:

在我的情况下,我使用了单例类,该类可以用作全局对象,从而允许从应用程序中的几乎所有位置访问数据。第一件事是建立一个单例类。请参阅页面," 我的Objective-C单例应该是什么样子?"而且,使对象可全局访问的方法只是将其导入appName_Prefix.pch中,该代码用于在每个类中应用import语句。为了访问该对象并使用它,我仅实现了类方法以返回共享实例,该实例包含其自己的变量

回答18:

如下所示在FirstViewController和SecondViewController之间传递数据

例如:

FirstViewController字符串值为

StrFirstValue = @"first";

所以我们可以使用下面的步骤在第二类中传递该值

1>我们需要在SecondViewController.h文件中创建字符串对象

NSString *strValue;

2>需要在.h文件中的声明下面声明属性

@property (strong, nonatomic)  NSString *strSecondValue;

3>需要在头声明下面的FirstViewController.m文件中合成该值

@synthesize strValue;

和在FirstViewController.h中:

@property (strong, nonatomic)  NSString *strValue;

4>在FirstViewController中,我们从哪个方法导航到第二个视图,请在该方法中编写以下代码。

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];

回答19:

我目前正在通过一个名为MCViewFactory的项目为该问题的开源解决方案做出贡献,该项目可在以下位置找到:

https://github.com/YetiHQ/manticore-iosviewfactory

这个想法是模仿Android的意图范式,它使用全局工厂来管理您正在查看的视图,并使用"意图"在视图之间切换和传递数据。所有文档都在github页面上,但是这里有一些要点:

在初始化工厂时,您可以在.XIB文件中设置所有视图并将其注册到应用程序委托中。

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

现在,在您的VC中,无论何时您想移至新的VC并传递数据,都可以创建一个新的Intent并将数据添加到其字典(savedInstanceState)中。然后,只需设置工厂的当前意图即可:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

所有符合此要求的视图都必须是MCViewController的子类,该类允许您覆盖新的onResume:方法,从而允许您访问传入的数据。

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

希望有些人发现此解决方案有用/有趣。

回答20:

在下一个viewcontroller.h上创建属性,并定义getter和setter。

在nextVC的NextVC.h中添加此属性

@property (strong, nonatomic) NSString *indexNumber;

添加

@synthesizeindexNumber;在NextVC.m中

最后

NextVC *vc=[[NextVC alloc]init];

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];

回答21:

快捷键5

很好 Matt Price的答案非常适合传递数据,但是我要重写它,因为它是最新的Swift版本,因为我相信新的程序员会发现它由于新的语法和方法/框架而面临挑战,就像原始文章在Objective-C中一样。

在视图控制器之间传递数据有多个选项。

  1. 使用导航控制器推送
  2. 使用Segue
  3. 使用代理人
  4. 使用通知观察器
  5. 使用块

我将使用最新的iOS Framework在Swift中重写他的逻辑


通过导航控制器推送传递数据从ViewControllerA到ViewControllerB

第1步。在ViewControllerB中声明变量

var isSomethingEnabled = false

第2步。在ViewControllerB的ViewDidLoad方法中打印变量

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

第3步。在ViewController中,在通过导航控制器时传递数据

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

所以这是完整的代码:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

通过Segue传递数据从ViewControllerA到ViewControllerB

第1步。从ViewControllerA到ViewControllerB创建Segue,并在Storyboard中提供Identifier = showDetailSegue,如下所示

第2步。在ViewControllerB中,声明一个名为 isSomethingEnabled 的可行对象并打印其值。

第3步。在ViewController中,传递Segue时传递isSomethingEnabled的值

所以这是完整的代码:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

通过代理传递数据从ViewControllerB到ViewControllerA

第1步。在ViewControllerB文件中但不在类外部声明协议 ViewControllerBDelegate

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

第2步。在ViewControllerB中声明代理变量实例

var delegate: ViewControllerBDelegate?

第3步。在ViewControllerB的viewDidLoad方法内部发送代表数据

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

第4步。在ViewControllerA中确认ViewControllerBDelegate

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

第5步。确认您将在ViewControllerA中实现委托

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

第6步。实现在ViewControllerA中接收数据的委托方法

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

所以这是完整的代码:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

通过通知观察器传递数据从ViewControllerB到ViewControllerA

步骤1。在ViewControllerB的Notification观察器中设置和发布数据

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

步骤2。在ViewControllerA中添加通知观察器

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

第3步。在ViewControllerA中接收通知数据值

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

所以这是完整的代码:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

通过数据块传递数据从ViewControllerB到ViewControllerA

第1步。在ViewControllerB中声明块

varauthorizationCompletionBlock:(((Bool)->()))? = {_ in}

第2步。在ViewControllerB的块中设置数据

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

第3步。在ViewControllerA中接收块数据

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

所以这是完整的代码:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

您可以找到完整的我的GitHub上的示例应用程序,如果对此有任何疑问,请告诉我。

回答22:

有很多方法可以做到这一点,选择正确的方法很重要。最大的架构决策之一可能取决于如何在整个应用程序中共享或访问模型代码。

不久前,我写了一篇关于此的博客文章:共享模型代码。这是一个简短的摘要:

共享数据

一种方法是在视图控制器之间共享指向模型对象的指针。

  • 在视图控制器(在导航或标签栏控制器中)上进行蛮力迭代以设置数据
  • 在prepareForSegue(如果是情节提要)或init(如果是程序性)中设置数据

因为准备好进行隔离是最常见的,所以这里是一个示例:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

独立访问

另一种方法是一次处理一个充满数据的屏幕,而不是将视图控制器彼此耦合,而是将每个视图控制器耦合到它们可以独立获取的单个数据源。

我看到的最常见的方式是 singleton 实例。因此,如果您的单例对象是DataAccess,则可以在UIViewController的viewDidLoad方法中执行以下操作:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

有些附加工具也可以帮助传递数据:

  • 键值观察
  • NSNotification
  • 核心数据
  • NSFetchedResultsController
  • 数据源

核心数据

Core Data的好处是它具有逆向关系。因此,如果您只想给NotesViewController提供notes对象,则可以使用它,因为它与笔记本之类的东西具有相反的关系。如果您需要NotesNoteController中笔记本上的数据,则可以通过执行以下操作来回退对象图:

let notebookName = note.notebook.name

在我的博客文章中了解有关此内容的更多信息:共享模型代码 < / p>

回答23:

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;

回答24:

委派是使用.xib文件时执行此类操作的唯一一种解决方案,但是上述所有答案均针对您需要使用委派的.xibs文件的storyboard。那是您唯一的解决方案。

另一种解决方案是使用单例类模式对其进行一次初始化,然后在整个应用程序中使用它。

回答25:

如果要将数据从ViewControlerOne传递到ViewControllerTwo,请尝试这些。

在ViewControlerOne.h中完成这些操作

 @property (nonatomic, strong) NSString *str1;

在ViewControllerTwo.h中完成这些操作

 @property (nonatomic, strong) NSString *str2;

在ViewControllerTwo.m中合成str2

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

在ViewControlerOne.m中执行这些操作

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

在按钮单击事件上执行此操作。

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

在ViewControllerTwo.m中完成这些操作

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}

回答26:

您可以将数据保存在App委托中,以跨应用程序中的视图控制器进行访问。您要做的就是创建一个应用程序委托的共享实例

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

例如

如果声明了NSArray对象*arrayXYZ,则可以通过appDelegate.arrayXYZ

在任何视图控制器中访问它

回答27:

如果您想将数据从一个发送到另一个viewController,请采用以下方法:

假设我们有viewControllers:ViewController和NewViewController。

在ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

在ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

在NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

在NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

因此,我们可以将数据从一个ViewController传递到另一个ViewController ...

回答28:

我喜欢基于NSProxy的Model对象和Mock对象的想法,如果用户选择的内容可以取消,则提交或丢弃数据。

由于数据是单个对象或几个对象,因此很容易传递数据,如果您说UINavigationController控制器,则可以将对模型的引用保留在内部,并且所有推入的视图控制器都可以直接从导航控制器访问它。

回答29:

我已经看到很多人使用didSelectRowAtPath方法使它复杂化。我在示例中使用的是Core Data。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

方法内的4行代码就完成了。

回答30:

这个问题有很多答案,它们提供了许多确实可以执行视图控制器通信的方法,但是我看不到任何地方提到哪个实际上最适合使用,哪个应该避免。

在实践中,我认为仅建议几种解决方案:

  • 要转发数据:
      使用情节提要和脚本时,
    • 重写UIViewControllerprepare(for:sender:)方法
    • 在执行视图控制器转换代码时通过初始化器或属性传递数据
  • 向后传递数据
    • 更新应用共享状态(您可以使用上述任何一种方法在视图控制器之间传递状态)
    • 使用委托
    • 使用轻松的搜索方式

建议不要使用的解决方案:

  • 直接引用以前的控制器,而不使用委托
  • 通过单例共享数据
  • 通过应用程序委托传递数据
  • 通过用户默认设置共享数据
  • 通过通知传递数据

这些解决方案虽然可以短期使用,但引入了太多的依赖关系,这些依赖关系会混淆应用程序的体系结构,并在以后产生更多问题。

对于那些感兴趣的人,我写了一些文章来更深入地解决这些问题,并强调各种弊端:

回到顶部