这个问题在Stack Overflow上似乎很流行,所以我想我会尝试给出一个更好的答案,以帮助像我这样在iOS世界起步的人。
转发数据
将数据从另一个视图控制器转发到视图控制器。如果您想将对象/值从一个视图控制器传递到另一个视图控件,并将其推送到导航堆栈,则可以使用此方法。
对于本例,我们将使用ViewControllerA和ViewControllerB
要将BOOL值从ViewControllerA传递到ViewControllerB,我们将执行以下操作。
在ViewControllerB.h中为BOOL创建一个属性@属性(非原子,赋值)BOOL是SomethingEnabled;在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设置为BOOL值YES。
使用Segues转发数据
如果您使用的是情节提要,则很可能使用segue,需要使用此过程来传递数据。这与上述类似,但不是在推送视图控制器之前传递数据,而是使用名为
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
因此,要将BOOL从ViewControllerA传递到ViewControllerB,我们将执行以下操作:
在ViewControllerB.h中为BOOL创建一个属性@属性(非原子,赋值)BOOL是SomethingEnabled;在ViewControllerA中,您需要告诉它ViewControllerB,因此使用#import“ViewControllerB.h”在情节提要上创建从ViewControllerA到ViewControllerB的片段,并为其提供标识符。在本例中,我们将其称为“showDetailSegue”接下来,我们需要将该方法添加到ViewControllerA,在执行任何segue时调用该方法。因此,我们需要检测调用了哪个segue,然后采取措施。在我们的示例中,我们将检查“showDetailSegue”,如果执行了,我们将把BOOL值传递给ViewControllerB-(void)准备segue:(UIStoryboardSegue*)segue发件人:(id)发件人{if([segue.identifier isEqualToString:@“showDetailSegue”]){ViewControllerB*控制器=(ViewControllerB*)segue.destinationViewController;controller.isSomethingEnabled=是;}}
如果在导航控制器中嵌入了视图,则需要将上面的方法稍微更改为以下方法
-(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设置为BOOL值YES。
传回数据
要将数据从ViewControllerB传递回ViewControllerA,需要使用协议和委托或块,后者可以用作回调的松耦合机制。
为此,我们将使ViewControllerA成为ViewControllerB的委托。这允许ViewControllerB向ViewControllerA发回消息,使我们能够发回数据。
要使ViewControllerA成为ViewControllerB的委托,它必须符合我们必须指定的ViewControllerC协议。这告诉ViewControllerA它必须实现哪些方法。
在ViewControllerB.h中,在#import下方,但在@interface上方,指定协议。@类ViewControllerB;@协议ViewControllerBDLegate<NSObject>-(void)addItemViewController:(ViewControllerB*)控制器didFinishEnteringItem:(NSString*)项;@完接下来仍然在ViewControllerB.h中,您需要设置委托属性并在ViewController B.m中进行合成@属性(非原子,弱)id<ViewControllerBDLegate>委托;在ViewControllerB中,当我们弹出视图控制器时,我们调用代理上的消息。NSString*itemToPassBack=@“将此值传递回ViewControllerA”;[self.delegate addItemViewController:self-didFinishEnteringItem:itemToPassBack];这就是ViewControllerB。现在在ViewControllerA.h中,告诉ViewControllerA导入ViewControllerB并遵守其协议。#import“ViewControllerB.h”@界面ViewControllerA:UIViewController<ViewControllerBDLegate>在ViewControllerA.m中,根据我们的协议实现以下方法-(void)addItemViewController:(ViewControllerB*)控制器didFinishEnteringItem:(NSString*)项{NSLog(@“这是从ViewControllerB%@返回的”,项);}在将viewControllerB推送到导航堆栈之前,我们需要告诉viewControllerB ViewControllerA是它的委托,否则我们将得到一个错误。ViewControllerB*ViewControllerB=[[ViewControllerB alloc]initWithNib:@“ViewControllerA”捆绑包:nil];viewControllerB.delegate=自身[[self-navigationController]pushViewController:viewControllerB动画:是];
工具书类
在《视图控制器编程指南》中使用委派与其他视图控制器通信代理模式
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传递到控制器A
定义块
@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h
添加块处理程序(侦听器)
需要值的地方(例如,需要ControllerA中的API响应,或者需要a上的ContorlerB数据)
// 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];
}
块的另一个工作示例