0
点赞
收藏
分享

微信扫一扫

(转)[ios]页面跳转传值参考

兮城 2022-08-24 阅读 100


​​http://stackoverflow.com/questions/5210535/passing-data-between-view-controllers​​

 

This question seems to be very popular here on stackoverflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.

I hope this answer is clear enough for people to understand and that I have not missed anything.

Passing Data Forward

Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.

For this example we will have ​​ViewControllerA​​ and ​​ViewControllerB​​To pass a ​​BOOL​​ value from ​​ViewControllerA​​ to ​​ViewControllerB​

  1. in

​ViewControllerB.h​

  1.  create a property for the 

​BOOL​

@property(nonatomic) BOOL *isSomethingEnabled;

  1. in

​ViewControllerA​

  1.  you need to tell it about 

​ViewControllerB​

#import "ViewControllerB.h"

Then where you want to load the view eg. ​​didSelectRowAtIndex​​ or some ​​IBAction​​ you need to set the property in ​​ViewControllerB​

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

This will set ​​isSomethingEnabled​​ in ​​ViewControllerB​​ to ​​BOOL​​ value ​​YES​​.

Passing Data Forward using Segues

If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called

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

So to pass a ​​BOOL​​ from ​​ViewControllerA​​ to ​​ViewControllerB​

  1. in

​ViewControllerB.h​

  1. create a property for the

​BOOL​

@property(nonatomic) BOOL *isSomethingEnabled;

  1. in

​ViewControllerA​

  1. you need to tell it about

​ViewControllerB​

#import "ViewControllerB.h"

  1. Create a the segue from

​ViewControllerA​

  1. to

​ViewControllerB​

  1. on the storyboard and give it an identifier, in this example we'll call it

​"showDetailSegue"​

  1. Next we need to add the method to

​ViewControllerA​

  1. that is called when any segue is performed, because of this we need to detect which segue was called and then do something. In our example we will check for

​"showDetailSegue"​

  1. and if thats performed we will pass our

​BOOL​

  1. value to

​ViewControllerB​

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender{if([segue.identifier isEqualToString:@"showDetailSegue"]){ViewControllerB*controller =(ViewControllerB*)segue.destinationViewController;
controller.isSomethingEnabled = YES;}}

If you have your views embedded in a navigation controller you need to change the method above slightly to the following

-(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;}}

This will set ​​isSomethingEnabled​​ in ​​ViewControllerB​​ to ​​BOOL​​ value ​​YES​​.

Passing Data Back

To pass data back from ​​ViewControllerB​​ to ​​ViewControllerA​​ you need to use Protocols and Delegates or Blocks, the latter can be used as a loosely coupled mechanism for callbacks.To do this we will make ​​ViewControllerA​​ a delegate of ​​ViewControllerB​​. This allows ​​ViewControllerB​​ to send a message back to ​​ViewControllerA​​For ​​ViewControllerA​​ to be delegate of ​​ViewControllerB​​ it must conform to ​​ViewControllerB​​'s protocol which we have to specify. This tells ​​ViewControllerA​

  1. In

​ViewControllerB.h​

  1. , below the

​#import​

  1. , but above

​@interface​

@classViewControllerB;@protocolViewControllerBDelegate<NSObject>-(void)addItemViewController:(ViewControllerB*)controller didFinishEnteringItem:(NSString*)item;@end

  1. next still in the

​ViewControllerB.h​

  1. you need to setup a

​delegate​

  1. property and synthesize in

​ViewControllerB.m​

@property(nonatomic, weak) id <ViewControllerBDelegate>delegate;

  1. In

​ViewControllerB​

  1. we call a message on the

​delegate​

NSString*itemToPassBack =@"Pass this value back to ViewControllerA";[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];

  1. That's it for

​ViewControllerB​

  1. . Now in

​ViewControllerA.h​

  1. , tell

​ViewControllerA​

  1. to import

​ViewControllerB​

#import "ViewControllerB.h"@interfaceViewControllerA:UIViewController<ViewControllerBDelegate>

  1. In

​ViewControllerA.m​

-(void)addItemViewController:(ViewControllerB*)controller didFinishEnteringItem:(NSString*)item
{NSLog(@"This was returned from ViewControllerB %@",item);}

  1. Before pushing

​viewControllerB​

  1. to navigation stack we need to tell

​ViewControllerB​

  1. that

​ViewControllerA​

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

References

  • ​​Using Delegation to Communicate With Other View Controllers​​ in theView Controller Programming Guide
  • ​​Delegate Pattern​​

Further Help

  • ​​Stackoverflow Documentation on Passing data between View Controllers​​

There are many answers to this questions offering many different ways to perform view controller communication that would indeed work, but I don't see anywhere mentioned which one are actually best to use and which ones to avoid.

In practice, in my opinion only a few solutions are recommended:

  • To pass data forward:
  • override the

​prepare(for:sender:)​

  • method of

​UIViewController​

  • pass data through an initializer or through properties when performing view controller transitions thtough code
  • To pass data backwards
  • update the app shared state (which you can pass forward between view controllers with either one of the methods above)
  • use delegation
  • use an unwind segue

Solutions I recommend NOT to use:

  • Referencing the previous controller directly instead of using delegation
  • Sharing data through a singleton
  • Passing data through the app delegate
  • Sharing data through the user defaults
  • Passing data through notifications

These solutions, although working in the short term, introduce too many dependencies that will garble the architecture of the app and create more problems later.

For those interested, I wrote some articles that address these points more in depth and highlight the various drawbacks:

  • ​​How iOS View Controllers Communicate With Each Other​​
  • ​​How to Structure the Code of iOS Apps​​
  • ​​Understanding the Core Architectural Principles of iOS Development with a Practical Example​​
举报

相关推荐

0 条评论