当前位置: 首页 > 面试题库 >

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

龙兴贤
2023-03-14
问题内容

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

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

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

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

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


问题答案:

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

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

转发数据

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

在这个例子中,我们将ViewControllerAViewControllerB

要将BOOL值从传递ViewControllerAViewControllerB我们,请执行以下操作。

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

这将设置isSomethingEnabledViewControllerBBOOL价值YES

使用Segues转发数据

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

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

因此,要将BOOLfrom 传递ViewControllerAViewControllerB我们,请执行以下操作:

  1. ViewControllerB.hBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. ViewControllerA你需要告诉它,ViewControllerB所以使用

    #import "ViewControllerB.h"
    
  3. 从创建的SEGUE ViewControllerAViewControllerB的故事板,并给它一个标识符,在这个例子中,我们叫它"showDetailSegue"

  4. 接下来,我们需要在ViewControllerA执行任何segue时将方法添加到被调用的方法,因此,我们需要检测调用了哪个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;
    }
}

这将设置isSomethingEnabledViewControllerBBOOL价值YES

传回数据

要将数据传递回ViewControllerBViewControllerA您,您需要使用 Protocols and Delegates
Blocks ,后者可以用作回调的松散耦合机制。

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

对于ViewControllerA成为一个代表ViewControllerB它必须符合ViewControllerB我们有指定的协议。这告诉ViewControllerA它必须实现哪些方法。

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

    @class ViewControllerB;
    

    @protocol ViewControllerBDelegate
    - (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

  5. ViewControllerA.m落实从我们的协议下面的方法

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    

    {
    NSLog(@”This was returned from ViewControllerB %@”,item);
    }

  6. 在推viewControllerB送到导航堆栈之前,我们需要告诉 ViewControllerBViewControllerA是它的委托,否则我们将得到一个错误。

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

块的另一个工作示例



 类似资料:
  • 问题内容: 我正在尝试将应用程序从Objective-C转换为Swift,但是我找不到如何使用Swift在视图之间传递数据。我的Objective-C代码是 这样做是从根本上获取变量TheNum,并将其传递给另一个视图控制器上的变量num。我知道这可能是一个简单的问题,但是我对Swift感到非常困惑,因此,如果有人可以解释他们如何将其更改为Swift,将不胜感激! 谢谢 问题答案: 假设我们站在

  • 问题内容: 我打算学习来自许多不同的MV *框架的AngularJS。我喜欢框架,但是在控制器之间传递数据时遇到了麻烦。 假设我有一个带有一些输入(input.html)的屏幕和一个控制器,比方说InputCtrl。 此视图上有一个按钮,可将您带到另一个屏幕,例如,使用控制器ApproveCtrl批准(approve.html)。 此ApproveCtrl需要来自InputCtrl的数据。在较大的

  • 我的任务是在javafx中单击3个按钮时调用一个方法,该方法执行的代码只需更改所单击按钮的颜色。 根据场景,我在fxml中创建了3个按钮,并在控制器中定义了一个方法。我的任务代码很简单 现在请您告诉我如何才能获得被点击的特定按钮ID。这里myButton是被点击的按钮的fx: id。 提前谢谢。

  • 问题内容: 我想知道在视图之间传递数据的“最佳”方法是什么。创建不可见字段并使用POST传递它是否更好,还是应该在URL中对其进行编码?还是有更好/更简便的方法? 问题答案: 在视图之间传递数据有多种方法。实际上,这与在两个不同的脚本之间传递数据的问题并没有什么大的不同,当然还引入了一些进程间通信的概念。我想到的一些事情是- GET请求 -第一个请求命中view1->将数据发送到浏览器->浏览器重

  • 问题内容: 我有一个基本的控制器来显示我的产品, 在我看来,我正在列表中显示此产品 我要尝试做的是,当某人单击产品名称时,我有另一个名为cart的视图,其中添加了该产品。 因此,我的疑问是,如何将这种点击产品从第一个控制器传递给第二个?我认为购物车也应该是控制器。 我使用指令处理click事件。我也觉得我应该使用服务来实现上述功能,只是想不通如何?因为购物车将是预定义的,所以添加的产品数可能是5/

  • 问题内容: 当使用AngularJS服务尝试在两个控制器之间传递数据时,我的第二个控制器在尝试从该服务访问数据时始终会收到未定义的信息。我猜这是因为第一个服务执行的是$ window.location.href,并且我认为这正在清除服务中的数据?我是否可以将URL更改为新位置,并将数据保留在第二个控制器的服务中?当我运行下面的代码时,第二个控制器中的警报始终未定义。 app.js(定义服务的位置)