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

2024-02-20

我是 iOS 和 Objective-C 的新手MVC https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller范式,我坚持以下几点:

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

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

我四处浏览,看到有些人在应用程序委托中声明了一个数组。我读到一些关于单身人士 https://en.wikipedia.org/wiki/Singleton_pattern,但我不明白这些是什么,并且我读了一些有关创建数据模型的内容。

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


这个问题在 Stack Overflow 上似乎很受欢迎,所以我想我会尝试给出一个更好的答案来帮助像我一样刚刚接触 iOS 世界的人。

转发数据

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

对于这个例子,我们将有ViewControllerA and ViewControllerB

要通过一个BOOL价值来自ViewControllerA to ViewControllerB我们将执行以下操作。

  1. in ViewControllerB.hBOOL

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

     #import "ViewControllerB.h"
    

然后是你想要加载视图的地方,例如,didSelectRowAtIndex或一些IBAction,您需要将属性设置为ViewControllerB在将其推入导航堆栈之前。

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

这将设置isSomethingEnabled in ViewControllerB to BOOL value YES.

使用 Segues 转发数据

如果您使用 Storyboard,您很可能会使用 Segue,并且需要此过程来向前传递数据。这与上面类似,但不是在推送视图控制器之前传递数据,而是使用名为的方法

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

所以要通过一个BOOL from ViewControllerA to ViewControllerB我们将执行以下操作:

  1. in ViewControllerB.hBOOL

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

     #import "ViewControllerB.h"
    
  3. 从以下位置创建转场ViewControllerA to ViewControllerB在故事板上并为其指定一个标识符。在这个例子中我们将其称为"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;
        }
    }

这将设置isSomethingEnabled in ViewControllerB to BOOL value YES.

传回数据

传回数据ViewControllerB to ViewControllerA你需要使用协议和代表 or Blocks,后者可以用作回调的松耦合机制。

为此,我们将制作ViewControllerA的代表ViewControllerB。这允许ViewControllerB发送消息回ViewControllerA使我们能够发回数据。

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

  1. In 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. In ViewControllerB我们打电话给一个消息delegate当我们弹出视图控制器时。

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

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

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

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

参考

  1. 使用委派与其他视图控制器进行通信 http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW9 in the 查看控制器编程指南
  2. 委托模式 https://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html

NS通知中心

这是传递数据的另一种方式。

// Add an 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 to 控制器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];
}

块的另一个工作示例 https://stackoverflow.com/a/49900404/3030400

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在视图控制器之间传递数据 的相关文章

  • CoreMediaIO,错误更新的属性 kCMIODevicePropertyDeviceIsRunningSomewhere

    当某些进程开始使用相机时 我需要接收一个事件 我通过 CMIOObjectGetPropertyData 完成此操作 但它不能正常工作 只有第一次访问时才是正确的值 我还尝试使用 CMIOObjectAddPropertyListenerB
  • PhoneGap/Cordova:如何使用cookies(iOS)?

    我有一个适用于 iOS 的 PhoneGap Corodova 项目 在 iOS 模拟器上构建时 我使用了 Jquery Cookies 它们很好 但是 既然我的设备上有该应用程序用于测试 它们就不再工作了 我猜这只是 iOS 不支持的东西
  • CloudKit 通过 cron 作业发送推送通知?

    我正在创建一个大学餐饮菜单应用程序 在其中我需要根据每日菜单发送推送通知 最初 我计划通过 Heroku 将用户数据存储在数据库中 并使用 cron 作业将数据库中的数据与每日菜单进行比较 并向用户发送适当的通知 然而 在 Cloudkit
  • UIPickerView - 对多行行使用自定义视图 - 需要布局建议

    我有一个 UIPickerView 它将为用户显示项目列表 我希望每个项目都显示为多行文本 每行使用不同的字体大小 一个粗略的模型如下所示 这将允许显示比默认 UIPickerView 的单行所能容纳的更多文本 bdesham 指出我在 U
  • :hover 状态在 iOS 上不会结束

    我有一个带有悬停状态的简单菜单
  • UISegmentedControl 中的自定义字体禁用调整FontSizeToFitWidth

    我已经为我的 UISegmentedControl 设置了自定义字体 但它似乎禁用了默认字体自动调整字体大小以适合宽度范围 Before After 这是我用来设置自定义字体的代码 UISegmentedControl segmentedC
  • 创建类似于邮件应用程序菜单的 iPhone 弹出菜单

    当您想要回复消息时 我想创建一个类似于邮件应用程序中的弹出菜单 我在多个应用程序中看到过这一点 所以我不确定框架中是否内置了某些内容或一些示例代码 在 Swift 中创建操作表 代码已使用 Swift 5 进行测试 从 iOS 8 开始 U
  • NSMutableArray 实例变量内存管理

    我正在做最后一点内存管理整理 但有些东西我不明白 我已经检查了所有文档 Stack Overflow 等 但仍然不明白 我怀疑这与数组有关 我有一个NSMutableArray作为实例变量 我用它来保存从另一个数组中的对象创建的对象 vie
  • 对于 Swift 中的计算器

    只是要警告你 我是 Swift 的新手 我仍在适应它的工作原理 我一直在尝试在课堂上完成这个计算器项目 问题是 我需要练习简化代码 现在 当按下数字按钮时 我将其保存在这样的数组中 IBAction func buttonPressed s
  • 释放 Core Foundation 对象引用

    我是否需要释放 Core Foundation 对象来清理内存 如果是这样 怎么办 例如 在代码中 ABAddressBookRef addressBook ABAddressBookCreate CFArrayRef peopleArra
  • Swift - 本地通知不会被触发

    我正在 Swift 3 中编码 我只是想发送通知now没有任何延迟或间隔 然而 通知永远不会被触发 这是我的代码 视图控制器代码 import UserNotifications class HomeViewController UIVie
  • tableView.dequeueReusableCellWithIdentifier() 导致应用程序挂起

    原帖 我们最近将我们的应用程序转换为 Swift 2 0 和 iOS9 我看到的一个奇怪的问题是调用 tableView dequeueReusableCellWithIdentifier 会导致应用程序挂在模拟器中 The code fu
  • iPhone iOS 保存从 UIImageJPEGRepresentation() 获得的数据第二次失败:ImageIO: CGImageRead_mapData 'open' failed

    我的 UIImage 操作遇到了一个奇怪的问题 我正在进行保管箱同步 并且必须将我的图像存储为本地文件 为此 我使用以下命令保存它们UIImagePNGRepresentation image or UIImageJPEGRepresent
  • 如何在 iOS 中查找蓝牙音频设备

    好的 我正在开发一个有趣的项目 该项目有一个障碍 我需要为我的 iOS 应用程序启用蓝牙音频支持 我遇到的障碍是我什至无法开始获取已连接的蓝牙音频设备的列表 即使我的 iPhone 5S 可以识别我的耳机 大约 3 4 岁的耳机 LG HB
  • 如何将导航栏大标题转换为多行,居中对齐

    我正在尝试设计具有多行居中大标题文本的视图控制器 就像苹果的 Ask Siri Settings gt General gt Keyboards gt About Ask Siri Dictation and Privacy 我可以使用以下
  • 从数组中获取随机字符串[重复]

    这个问题在这里已经有答案了 我试图从数组 firstArray 中获取随机字符串并将其打印在 UILabel label 中 我似乎无法弄清楚并且出现错误 感谢您的帮助 我尝试搜索但找不到任何最新的教程 方法 import UIKit cl
  • 如何在 iOS 上压缩 Realm DB?

    我想定期压缩 iOS 上的 Realm 实例以回收空间 我认为该过程是将数据库复制到临时位置 然后将其复制回来并使用新的default realm 文件 我的问题是Realm 其行为就像单例并回收对象 因此我无法真正关闭它并告诉它打开新的
  • 最近打开的应用程序[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 有什么方法可以获取最近打开的应用程序 例如 4 个 的列表吗 如果是这样 怎么办 可可麦克 看看LaunchServices LSSh
  • 是否可以使“HTML 到语音”与“文本到语音”相同?

    我有一个奇怪的要求 在我现有的应用程序中我有Text2Speech为此 我使用了AVSpeechSynthesizer 到语音文本 但现在要求发生了变化 现在我需要将 HTML 文件数据转换为文本 例如HTML2Speech 我们可以想到的
  • UITableview 中的水平和垂直滚动[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 I want to make a lineup for a festival You can see what I want to a

随机推荐