使用prepareForSegue方法时,IBOutlet属性不会更新

Sha*_*osa 4 objective-c storyboard ios5 xcode4.2

我有问题将值传递给destinationViewController的IBOutlet属性,但它在普通属性上工作正常,请参阅下面的代码

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"NewsCellToDetail"]) {        
    testViewController *viewController = segue.destinationViewController;
    viewController.titleLabel.text = @"test"; // set the IBOutlet label text to something
    NSLog(@"%@",viewController.titleLabel.text); // this will output to nil
    viewController.textTest = @"testing2"; // set the property to something
    NSLog(@"%@", viewController.textTest) // this will output the string testing2
}
Run Code Online (Sandbox Code Playgroud)

这是头文件testviewcontroller.h的代码

#import <UIKit/UIKit.h>
@interface NewsDetailViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
@property (strong, nonatomic) NSString *textTest;
@end
Run Code Online (Sandbox Code Playgroud)

我已经合成了这两个属性.

谢谢您的帮助.

Mat*_* S. 15

我有点迟到这个答案,但我最近遇到了这个问题,如果我们仍然手动实例化事情而不是让故事板处理它,原因就显而易见了.它恰好与您在手动实例化视图控制器时从未操纵视图的原因相同:segue的destinationViewController尚未调用loadView:但是,在故事板中,它通过反序列化关联的nib中的所有视图对象来运行.

一个非常简单的方法来看到这个:

  1. 创建两个ViewController场景(ViewController1和ViewController2)
  2. 向ViewController1添加一个按钮,从按钮向ViewController2添加一个动作segue
  3. 向ViewControler2添加子视图,并向该子视图添加IBOutlet
  4. 在prepareConSegue:ViewController1中,尝试引用ViewController2的子视图出口 - 你会发现它是nil并且它的frame/bounds为null.

这是因为ViewController2的视图尚未添加到视图堆栈中,但控制器已初始化.因此,您永远不应该尝试在prepareForSegue中操作ViewController2的视图:否则您执行的任何操作都将丢失.参考Apple的ViewController编程指南,了解生命周期:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

这里接受的答案是强制loadView在prepareForSegue中运行:通过访问目标的.view属性,这就是出现故障的原因,并且如果你试图做任何类型的事情,将会有未知/难以重现的结果在viewDidLoad中查看操作以考虑任何数据加载,因为没有将视图加载到viewStack,对框架引用的父视图的任何引用都将为nil.

TL; DR; - 如果您有像OP一样需要传递的数据,请使用目标上的公共属性进行设置,然后在目标控制器的viewDidLoad中将该数据加载到视图的子视图中.

编辑:

类似的问题 - IBOutlet在自定义UIView中是零(使用STORYBOARD)

您可能还希望利用viewDidLayoutSubviews:进行任何子视图操作.


Ste*_*ang 10

我最近遇到了同样的问题.但是当我逐步调试它时,我发现了一个可能的原因.(对不起,我也是Objective C的新手,所以我的以下解释可能不那么准确和专业......我以前的背景主要是网页开发.)

如果在您调用的行之后设置断点

testViewController *viewController = segue.destinationViewController;

在构建和运行项目时,您会发现destinationViewController中的UITextField属性未在断点处分配和启动(内存为0x0).同时NSString属性已经分配并初始化(因此您可以设置其值).

我认为UITextfield可能是子视图,所以它只在启动其父视图(目标视图)时才会启动.但是NSString是一个与任何视图都没有关联的属性,所以它是由声明它的视图控制器分配和启动的.

当我对此进行进一步测试时,我发现了一个非常有趣的事情:第二个视图在- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender运行期间加载.我做了如下测试代码:

在第一个视图控制器.m文件中:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSLog(@"1. %@, %@",[segue identifier],segue.destinationViewController);

    Scene2Controller *scene2ViewController = [segue destinationViewController];
    [txtScene2 resignFirstResponder];

    NSLog(@"2. scene2ViewController: %@", scene2ViewController);
    NSLog(@"3. txtScene1: %@; passValue: %@", [scene2ViewController txtScene1], scene2ViewController.passValue);
    NSLog(@"4. View2: %@; passValue: %@", [scene2ViewController view], scene2ViewController.passValue);
    NSLog(@"5. txtScene1: %@; passValue: %@", [scene2ViewController txtScene1], scene2ViewController.passValue);

    //txtScene1 is the UITextfield property I declared in the second view controller
    //txtScene2 is the UITextfield property I declared in the first view controller
    //passValue is the NSString property I declared in the second view controller 

}
Run Code Online (Sandbox Code Playgroud)

在第二个视图控制器.m文件中:

- (void)viewDidLoad
{
    NSLog(@"6. txtScene1: %@; passValue: %@", txtScene1,passValue);


    [super viewDidLoad];

}
Run Code Online (Sandbox Code Playgroud)

注意到我在NSLog消息之前添加了序列号.我发现最终的对数结果序列是1,2,3,6,4,5而不是1,2,3,4,5,6.在log 3中,txtScene1结果为null(未启动),但在log 4(加载第二个视图)之后,在log 5中,txtScene1为非null且已启动.这表明在segue执行期间加载了第二个视图.所以我想在segue过渡期间,第二个视图控制器对象的启动序列将是:第二个视图控制器 - > NSString属性(和其他类似属性,如NSInteger等) - >第二个视图 - > UITextfield属性(和其他子视图属性).

所以我在第一个视图控制器.m文件中更改了我的代码,如下所示:

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

    Scene2Controller *scene2ViewController = [segue destinationViewController];
    [txtScene2 resignFirstResponder];

    if ([scene2ViewController view]) {
        if ([txtScene2.text isEqualToString:@""]) {
            scene2ViewController.txtScene1.text = @"No Value";
        } else {
            scene2ViewController.txtScene1.text = txtScene2.text;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

然后此代码正常工作,并将值直接传递给第二个视图中的UITextfield属性.

希望以上解释清楚,对您有所帮助.