这个问题在 Stack Overflow 上似乎很受欢迎,所以我想我会尝试给出一个更好的答案来帮助像我一样刚刚接触 iOS 世界的人。
转发数据
将数据从另一个视图控制器转发到视图控制器。如果您想将对象/值从一个视图控制器传递到另一个可能推送到导航堆栈的视图控制器,则可以使用此方法。
对于这个例子,我们将有ViewControllerA
and ViewControllerB
要通过一个BOOL
价值来自ViewControllerA
to ViewControllerB
我们将执行以下操作。
-
in ViewControllerB.h
为BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
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
我们将执行以下操作:
-
in ViewControllerB.h
为BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
in ViewControllerA
你需要告诉它ViewControllerB
,所以使用
#import "ViewControllerB.h"
-
从以下位置创建转场ViewControllerA
to ViewControllerB
在故事板上并为其指定一个标识符。在这个例子中我们将其称为"showDetailSegue"
-
接下来,我们需要添加该方法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
它必须实现哪些方法。
-
In ViewControllerB.h
, 以下#import
,但上面@interface
您指定协议。
@class ViewControllerB;
@protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
-
接下来依然在ViewControllerB.h
,你需要设置一个delegate
属性并合成ViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
-
In ViewControllerB
我们打电话给一个消息delegate
当我们弹出视图控制器时。
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
-
就这样了ViewControllerB
。现在在ViewControllerA.h
, tell ViewControllerA
导入ViewControllerB
并遵守其协议。
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
-
In ViewControllerA.m
从我们的协议中实现以下方法
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@", item);
}
-
推之前viewControllerB
我们需要告诉导航堆栈ViewControllerB
that ViewControllerA
是它的委托,否则我们会得到一个错误。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
参考
-
使用委派与其他视图控制器进行通信 http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW9 in the 查看控制器编程指南
- 委托模式 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