在视图控制器之间传递数据 [英] Passing Data between View Controllers
问题描述
我是iOS和Objective-C以及整个MVC范例的新手,我坚持以下内容:
我有一个视图,作为一个数据输入表单,我想让用户选择多个产品。产品在另一个视图中列出,带有 UITableViewController
,我启用了多项选择。
我的问题是,如何将数据从一个视图传输到另一个视图?我将在数组中的 UITableView
上保留选择,但是如何将其传递回上一个数据输入表单视图,以便它可以与另一个一起保存提交表格时数据到核心数据?
我已经四处浏览并看到有人在应用代表中声明了一个数组。我读了一些关于Singletons的内容,但不明白这些是什么,我读了一些关于创建数据模型的内容。
执行此操作的正确方法是什么?我去了吗?
这个问题似乎在stackoverflow上非常受欢迎,所以我想我会尝试给出一个更好的回答帮助像我这样的iOS世界中的人们。
我希望这个答案足够清楚,让人们理解并且我没有错过任何东西。
传递数据
将数据从另一个视图控制器传递到视图控制器。如果要将对象/值从一个视图控制器传递到另一个可能正在推送到导航堆栈的视图控制器,则可以使用此方法。
为此例如,我们将 ViewControllerA
和 ViewControllerB
要通过一个 BOOL
从 ViewControllerA
到 ViewControllerB
我们会做的在 ViewControllerB.h
为<创建属性code> BOOL
@property(nonatomic,assign)BOOL isSomethingEnabled;
在 ViewControllerA
中你需要告诉它 ViewControllerB
所以使用
#importViewControllerB.h
然后你要加载视图的地方,例如。 didSelectRowAtIndex
或某些 IBAction
您需要在 ViewControllerB
然后将其推送到导航堆栈。
ViewControllerB * viewControllerB = [[ViewControllerB alloc] initWithNib:@ViewControllerB包:零];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
这将在<$ c中设置 isSomethingEnabled
$ c> ViewControllerB 到 BOOL
值是
。
使用Segues传递数据
如果您正在使用您最有可能使用segues的故事板,并且需要此过程来传递数据。这与上面的类似,但不是在推动视图控制器之前传递数据,而是使用名为
的方法 - ( void)prepareForSegue:(UIStoryboardSegue *)segue发送者:(id)发件人
所以传递 BOOL
从 ViewControllerA
到 ViewControllerB
我们将执行以下操作:
-
在
ViewControllerB.h
为BOOL
@property(nonatomic,assign)BOOL isSomethingEnabled;
-
在
ViewControllerA
中你需要告诉它ViewControllerB
所以使用#importViewControllerB.h
-
从
ViewControllerA $ c $创建一个segue故事板上的c>到
ViewControllerB
并给它一个标识符,在这个例子中我们称之为showDetailSegue
-
接下来我们需要将方法添加到执行任何segue时调用的
ViewControllerA
,因为我们需要检测哪个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
inViewControllerB
toBOOL
valueYES
。
传递数据
要将数据从 ViewControllerB
传递回 ViewControllerA
,您需要使用协议和代理或 Blocks ,后者可以用作松散耦合的回调机制。
要做到这一点,我们将使 ViewControllerA
ViewControllerB
的委托。这允许 ViewControllerB
将消息发送回 ViewControllerA
,使我们能够发回数据。
对于 ViewControllerA
作为 ViewControllerB
的委托,它必须符合 ViewControllerB
我们必须指定的协议。这告诉 ViewControllerA
它必须实现哪些方法。
-
In
ViewControllerB.h
,低于#import
,但高于@interface
你指定协议。@class ViewControllerB;
@protocol ViewControllerBDelegate< NSObject>
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
-
下一步仍在
ViewControllerB中。 h
您需要设置委托
属性并在中合成ViewControllerB.m
@property(非原子,弱)id< ViewControllerBDelegate>代表;
-
在
ViewControllerB
中我们称之为当我们弹出视图控制器时,委托
上的消息。NSString * itemToPassBack = @将此值传递回ViewControllerA;
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
-
这是
ViewControllerB
。现在在ViewControllerA.h
中,告诉ViewControllerA
导入ViewControllerB
并符合其协议。#importViewControllerB.h
@interface ViewControllerA:UIViewController < ViewControllerBDelegate>
-
在
ViewControllerA.m
中实施我们的协议中的以下方法- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@这是从ViewControllerB%@返回的,项目);
}
-
在推送
viewControllerB $ c之前$ c>到导航堆栈我们需要告诉
ViewControllerB
ViewControllerA
是它的委托,否则我们会收到错误。ViewControllerB * viewControllerB = [[ViewControllerB alloc] initWithNib:@ViewControllerBbundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
< h3>参考文献
I'm new to iOS and Objective-C and the whole MVC paradigm and I'm stuck with the following:
I have a view that acts as a data entry form and I want to give the user the option to select multiple products. The products are listed on another view with a UITableViewController
and I have enabled multiple selections.
My question is, how do I transfer the data from one view to another? I will be holding the selections on the UITableView
in an array, but how do I then pass that back to the previous data entry form view so it can be saved along with the other data to Core Data on submission of the form?
I have surfed around and seen some people declare an array in the app delegate. I read something about Singletons but don't understand what these are and I read something about creating a data model.
What would be the correct way of performing this and how would I go about it?
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
we would do the following.
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
so use an#import "ViewControllerB.h"
Then where you want to load the view eg.
didSelectRowAtIndex
or someIBAction
you need to set the property inViewControllerB
before you push it onto nav stack.ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.isSomethingEnabled = YES; [self pushViewController:viewControllerB animated:YES];
This will set
isSomethingEnabled
inViewControllerB
toBOOL
valueYES
.
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
we would do the following:
in
ViewControllerB.h
create a property for theBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
in
ViewControllerA
you need to tell it aboutViewControllerB
so use an#import "ViewControllerB.h"
Create a the segue from
ViewControllerA
toViewControllerB
on the storyboard and give it an identifier, in this example we'll call it"showDetailSegue"
Next we need to add the method to
ViewControllerA
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"
and if thats performed we will pass ourBOOL
value toViewControllerB
-(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
inViewControllerB
toBOOL
valueYES
.
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
enabling us to send data back.
For ViewControllerA
to be delegate of ViewControllerB
it must conform to ViewControllerB
's protocol which we have to specify. This tells ViewControllerA
which methods it must implement.
In
ViewControllerB.h
, below the#import
, but above@interface
you specify the protocol.@class ViewControllerB; @protocol ViewControllerBDelegate <NSObject> - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; @end
next still in the
ViewControllerB.h
you need to setup adelegate
property and synthesize inViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
In
ViewControllerB
we call a message on thedelegate
when we pop the view controller.NSString *itemToPassBack = @"Pass this value back to ViewControllerA"; [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
That's it for
ViewControllerB
. Now inViewControllerA.h
, tellViewControllerA
to importViewControllerB
and conform to its protocol.#import "ViewControllerB.h" @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
In
ViewControllerA.m
implement the following method from our protocol- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog(@"This was returned from ViewControllerB %@",item); }
Before pushing
viewControllerB
to navigation stack we need to tellViewControllerB
thatViewControllerA
is its delegate, otherwise we will get an error.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 the View Controller Programming Guide
- Delegate Pattern
这篇关于在视图控制器之间传递数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!