如何访问UINavigationController中的先前视图元素

我有一个UINavigationController,我在其中加载不同的视图控制器。 我想知道如何访问我之前视图的元素(如标签等)。 这是一个例子。

查看myLabel.text = @“第一个视图”;

(用户移动到查看B)

视图B(用户输入了一条消息,我需要在视图A中显示)类似于ViewA.myLabel.text = @“用户输入的消息”

我尝试过很多东西但却找不到任何有用的东西。 请帮忙..

我使用没有ARC的Xcode 4而没有故事板。

谢谢山姆


编辑:

我想更新View A的viewController中声明的属性,而不是直接更新标签。 我的标签使用该属性进行更新。 就像在推动viewController时一样,我们可以传递如下的值。

ViewA *myView = [[ViewA alloc] init]; myView.title = @"View B" ; myView.tableView.tag = 3; myView.myTextView.text = @"Some Text"; [self.navigationController pushViewController:myView animated:YES]; [myView release]; 

在弹出ViewB并返回ViewA时,有没有办法将这些值传递给ViewA的ViewController属性?

实际场景如下:用户获取和选择在textView中编写消息,或者他可以使用预定义的模板。 如果他点击模板按钮,他将被带到预定义模板列表,在那里他可以选择任何预定义的消息。 现在我希望当用户点击任何预定义消息时,弹出包含预定义消息列表的视图,并且在主视图的textView中自动填充他选择的消息。 实现这一目标的最佳方法是什么?

TIA Sam

您应该将AViewController设置为BViewController的委托,以便在特定事件之后将其发回消息。 使用委托还可以更好地解耦ViewControllers。

在BViewController中,定义如下协议:

BViewController.h:

 @protocol BViewControllerDelegate  - (void)viewB:(UIViewController *)didEnterMessage:(NSString *)message; @end 

并添加委托属性:

 @property (nonatomic, weak) id  delegate; 

当用户在BViewController中输入消息并点击弹出BViewController以显示给AViewController的按钮时,执行以下操作:

 - (IBAction)messageEntered { if ([self.delegate respondsToSelector:@selector(viewB:didEnterMessage:)]) { [self.delegate viewB:self didEnterMessage:self.yourTextField.text]; } } 

您的AViewController应该像这样实现BViewControllerDelegate协议:

AViewController.h:

 @interface AViewController  

当AViewController创建BViewController时,它应该在呈现之前将自己设置为其委托。 可能看起来像这样:

 BViewController *bvc = [[BViewController alloc] init…]; bvc.delegate = self; 

最后,你的AViewController应该实现viewB:didEnterMessage:方法:

 - (void)viewB:(UIViewController *)didEnterMessage:(NSString *)message { self.myLabel.text = message; } 

这是最干净的方法,恕我直言。

您可以获取导航控制器的viewControllers属性并使用它,可能是这样的:

 UILabel *label = ((SomeViewController *)[self.navigationController.viewControllers objectAtIndex:1]).myLabel; 

但是,这不可靠。 由于“上一个”视图不在屏幕上,因此系统可以卸载它以释放内存。 然后label将是nil

您可以通过访问视图控制器的view属性来强制其他视图控制器重新加载其视图(如果已卸载)。

但真的这就像糟糕的设计。 当视图控制器的视图不在屏幕上时,您几乎不应该尝试访问视图控制器的视图。 还记得如果视图在屏幕外,系统如何卸载视图控制器的视图? 如果该视图下的某些UILabel包含唯一的重要数据副本,那么该数据现在已经消失了!

任何重要数据都需要存储在视图以外的某个位置 – 可能存储在视图控制器的属性中,或存储在模型对象中。 您应该向视图控制器询问数据,或者询问包含数据的模型对象。 视图控制器的视图对象应该几乎总是被视为视图控制器的私有实现细节,而不是暴露给其他类。

编辑

您的问题令人费解,因为您谈论弹出ViewB并返回ViewA ,但您的代码只会创建并推送ViewAViewB中未提及ViewB

我将假设您的ViewA创建并推送ViewB。 所以你应该给ViewB一个ViewA类型的ViewA ,如下所示:

 @class ViewA; // forward declaration to avoid circular imports @interface ViewB @property (weak, nonatomic) ViewA *aView; 

然后,当ViewA创建ViewB实例时,您可以设置ViewB属性:

 @implementation ViewA - (void)pushViewB { ViewB *bView = [[ViewB alloc] init]; bView.aView = self; [self.navigationController pushViewController:bView animated:YES]; } 

现在,您的ViewB可以访问创建它的ViewA ,并可以设置该ViewA的属性。

如果要编写好的代码,则应遵循模型 – 视图 – 控制器模式。 这是相当不错的tutrial http://www.cocoalab.com/?q=node/24在几个词中,它意味着你不应该在View中存储数据(并且视图也不应该充当控制器)。 我建议你编写一个自定义类来进行这种管理(存储数据并将其从一个视图传递到另一个视图)。 如果它只是一个测试应用程序,那么您可以使用UINavigationController的viewControllers属性来访问导航堆栈中的控制器,或者只是创建一个变量来存储此数据,例如,在视图B中

 - (void)textFieldDidEndEditing:(UITextField *)textField { stringToDisplayInFirstController = textField.text; NSArray * arrayOfControllers = self.navigationController.viewControllers; UIViewController * viewControllerA = [arrayOfControllers objectAtIndex:[arrayOfControllers count]-1]; viewControllerA.label.text = stringToDisplayInFirstController; }