这个问题在StackOverflow上似乎很受欢迎,所以我想我会尝试给出一个更好的答案,帮助像我这样在iOS世界起步的人。
向前传递数据
将数据从另一个视图控制器向前传递到视图控制器。如果您想将对象/值从一个视图控制器传递到另一个可能推送到导航堆栈的视图控制器,则可以使用此方法。
对于这个例子,我们将有
ViewControllerA
和
ViewControllerB
传递
BOOL
值来自
ViewControllerA
到
视图控制器B
我们将执行以下操作。
-
在里面
ViewControllerB.h
为创建属性
BOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
-
在里面
ViewControllerA
你需要告诉它
视图控制器B
所以使用
#import "ViewControllerB.h"
然后,在要加载视图的位置,例如,
didSelectRowAtIndex
或者一些
IBAction
,您需要在中设置属性
视图控制器B
然后将其推到导航堆栈上。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
这将设置
isSomethingEnabled
在里面
视图控制器B
到
BOOL
价值
YES
。
使用分段向前传递数据
如果您正在使用情节提要,则很可能使用分段,并且需要此过程来向前传递数据。这与上面的类似,但不是在推送视图控制器之前传递数据,而是使用一个名为
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
所以要通过
BOOL
从…起
ViewControllerA
到
视图控制器B
我们将执行以下操作:
-
在里面
ViewControllerB。h
为创建属性
BOOL
@属性(nonatomic,assign)BOOL为SomethingEnabled;
-
在里面
ViewControllerA
你需要告诉它
视图控制器B
,所以使用
#导入“ViewControllerB.h”
-
从创建分段
ViewControllerA
到
视图控制器B
并给它一个标识符。在这个例子中,我们称之为
"showDetailSegue"
-
接下来,我们需要将该方法添加到
ViewControllerA
当执行任何segue时调用。因此,我们需要检测调用了哪个segue,然后采取措施。在我们的示例中,我们将检查
“showDetailSegue”
如果能做到这一点,我们将通过
BOOL
值到
视图控制器B
-(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;
}
}
这将设置
是否启用了某些功能
在里面
视图控制器B
到
BOOL
价值
是的
。
将数据传回
从传递回数据
视图控制器B
到
ViewControllerA
你需要使用
协议和代表
或
方块
,后者可以用作回调的松耦合机制。
为此,我们将
ViewControllerA
的代表
视图控制器B
。这允许
视图控制器B
将消息发送回
ViewControllerA
使我们能够发回数据。
对于
ViewControllerA
成为的代表
视图控制器B
它必须符合
视图控制器B
的协议,我们必须指定。这告诉
ViewControllerA
它必须实现哪些方法。
-
在里面
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;
-
在里面
视图控制器B
我们在上调用消息
代表
当我们弹出视图控制器时。
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
-
就这样
视图控制器B
。现在在
ViewControllerA.h
告诉
ViewControllerA
要导入
视图控制器B
并符合其协议。
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
-
在里面
ViewControllerA.m
从我们的协议中实现以下方法
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@", item);
}
-
推动前
viewControllerB
到导航堆栈,我们需要告诉
视图控制器B
那个
ViewControllerA
是它的委托,否则我们将得到一个错误。
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
参考文献
-
Using Delegation to Communicate With Other View Controllers
在中
查看控制器编程指南
-
Delegate Pattern
NSNotification中心
这是传递数据的另一种方式。
// 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];
}
Another Working Example for Blocks