在视图控制器之间传递数据 在iOS开发中,视图控制器之间的数据传递是一个常见需求。本文将详细介绍多种在视图控制器间传递数据的方法,包括正向传递、反向传递等。
正向传递数据 直接设置属性 若要将数据从一个视图控制器传递到另一个视图控制器,可直接设置目标视图控制器的属性。以下是示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 @interface ViewControllerB : UIViewController @property (nonatomic , assign ) BOOL isSomethingEnabled;@end #import "ViewControllerB.h" - (void )loadViewControllerB { ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil ]; viewControllerB.isSomethingEnabled = YES ; [self .navigationController pushViewController:viewControllerB animated:YES ]; }
使用Segue传递 若使用Storyboards,可利用Segue正向传递数据。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 @interface ViewControllerB : UIViewController @property (nonatomic , assign ) BOOL isSomethingEnabled;@end #import "ViewControllerB.h" - (void )prepareForSegue:(UIStoryboardSegue *)segue sender:(id )sender { if ([segue.identifier isEqualToString:@"showDetailSegue" ]) { ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController; controller.isSomethingEnabled = YES ; } }
反向传递数据 使用协议和代理 为实现从ViewControllerB
向ViewControllerA
反向传递数据,可使用协议和代理。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @class ViewControllerB ;@protocol ViewControllerBDelegate <NSObject > - (void )addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;@end @interface ViewControllerB : UIViewController @property (nonatomic , weak ) id <ViewControllerBDelegate> delegate;@end - (void )popViewController { NSString *itemToPassBack = @"Pass this value back to ViewControllerA" ; [self .delegate addItemViewController:self didFinishEnteringItem:itemToPassBack]; [self .navigationController popViewControllerAnimated:YES ]; }#import "ViewControllerB.h" @interface ViewControllerA : UIViewController <ViewControllerBDelegate >@end - (void )addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog (@"This was returned from ViewControllerB %@" , item); } - (void )pushViewControllerB { ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil ]; viewControllerB.delegate = self ; [[self navigationController] pushViewController:viewControllerB animated:YES ]; }
使用Block Block是匿名函数,也可用于反向传递数据。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @property void (^selectedVoucherBlock)(NSString *); - (void )viewDidLoad { [super viewDidLoad]; __unsafe_unretained typeof (self ) weakSelf = self ; self .selectedVoucherBlock = ^(NSString *voucher) { weakSelf->someLabel.text = voucher; }; } - (void )pushToControllerB { ControllerB *vc = [[ControllerB alloc] initWithNib:@"ControllerB" bundle:nil ]; 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 ]; }
使用NSNotificationCenter传递数据 可使用NSNotificationCenter
在不同类之间传递数据。示例如下:
1 2 3 4 5 6 7 8 9 10 11 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (handleDeepLinking:) name:@"handleDeepLinking" object:nil ]; - (void )handleDeepLinking:(NSNotification *) notification { id someObject = notification.object; }id someObject; [NSNotificationCenter .defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];
Swift实现示例 正向传递数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import UIKitclass FirstViewController : UIViewController { @IBOutlet weak var textField: UITextField ! override func prepare (for segue : UIStoryboardSegue , sender : Any ? ) { if segue.identifier == "showSecondViewController" { let secondViewController = segue.destination as! SecondViewController secondViewController.receivedString = textField.text! } } }import UIKitclass SecondViewController : UIViewController { @IBOutlet weak var label: UILabel ! var receivedString = "" override func viewDidLoad () { super .viewDidLoad() label.text = receivedString } }
反向传递数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import UIKitclass FirstViewController : UIViewController , DataEnteredDelegate { @IBOutlet weak var label: UILabel ! override func prepare (for segue : UIStoryboardSegue , sender : Any ? ) { if segue.identifier == "showSecondViewController" { let secondViewController = segue.destination as! SecondViewController secondViewController.delegate = self } } func userDidEnterInformation (info : String ) { label.text = info } }import UIKitprotocol DataEnteredDelegate : AnyObject { func userDidEnterInformation (info : String ) }class SecondViewController : UIViewController { weak var delegate: DataEnteredDelegate ? = nil @IBOutlet weak var textField: UITextField ! @IBAction func sendTextBackButton (sender : AnyObject ) { delegate? .userDidEnterInformation(info: textField.text! ) _ = self .navigationController? .popViewController(animated: true ) } }
最佳实践 正向传递数据时,若使用Storyboards,推荐使用prepareForSegue
方法;若不使用Storyboards,可直接设置属性。 反向传递数据时,若数据传递逻辑简单,可使用Block;若逻辑复杂,推荐使用协议和代理。 使用NSNotificationCenter
时,注意在合适的时机移除观察者,避免内存泄漏。 常见问题 代理方法未调用 可能是未正确设置代理,需确保在创建目标视图控制器时,将源视图控制器设置为其代理。
通知未收到 可能是通知名称拼写错误,或未正确注册观察者。需检查通知名称和注册代码。