在调用performSegueWithIdentifier之后获取重复的UIViewController实例

时间:2014-12-18 15:04:34

标签: ios objective-c iphone uiviewcontroller segue

**********************更新:问题已经解决!! 不回复。谢谢! :)


我正在尝试为名为RootViewController的UIViewController实现多个方向。它是应用程序中的根视图控制器。

我按照Apple教程(https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html)中的说明操作,并在RootViewController类中实现以下代码:

- (void) viewDidLoad {
    ...
    // detect orientation changed
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(orientationChanged:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:[UIDevice currentDevice]];

    ....
}

- (void) orientationChanged:(NSNotification *)note {
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    log(@"self: %@, orientation: %d", self, (int)orientation);

    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView) {
        log(@"show landscape view");
        [self performSegueWithIdentifier:@"go_landscape" sender:self];
        isShowingLandscapeView = YES;
    } else if (UIDeviceOrientationIsPortrait(deviceOrientation) && isShowingLandscapeView) {
        log(@"show portrait view");
        [self dismissViewControllerAnimated:NO completion:nil];
        isShowingLandscapeView = NO;
    }
}

当我尝试将模拟器旋转到横向模式时,会调用orientationChanged方法。但是当我将其旋转回来时,我看到一个非常奇怪的情况:RootViewController获得一个重复的实例(原始实例id = 0x7fc4eb813a00,并且在下面的日志中重复的一个是0x7fc4eb081800)。

-[RootViewController orientationChanged:] [Line 796] self: <RootViewController:
0x7fc4eb813a00>, orientation: 1
-[RootViewController orientationChanged:] [Line 796] self: <RootViewController:   
0x7fc4eb813a00>, orientation: 3
-[RootViewController orientationChanged:] [Line 800] show landscape view
-[RootViewController orientationChanged:] [Line 796] self: <RootViewController: 
0x7fc4eb813a00>, orientation: 1
-[RootViewController orientationChanged:] [Line 804] show portrait view
-[RootViewController orientationChanged:] [Line 796] self: <RootViewController: 
0x7fc4eb081800>, orientation: 1

如果我再次将其旋转到横向模式,应用程序将崩溃为以下日志。 (重复的那个没有segue。)

-[RootViewController orientationChanged:] [Line 796] self: <RootViewController: 
0x7fc4eb081800>, orientation: 3
-[RootViewController orientationChanged:] [Line 800] show landscape view
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: 'Receiver (<RootViewController: 0x7fc4eb081800>) has no segue with 
identifier 'go_landscape''
*** First throw call stack:

故事板:

enter image description here

segue设置:

enter image description here

我真的不知道为什么会这样。我创建了一个新项目来测试方向改变实现,不会发生奇怪的情况。有任何调查方向吗?

3 个答案:

答案 0 :(得分:1)

当您切换到横向时,您已发布的代码是DESIGNED以创建新的视图控制器。 performSegue方法创建一个新的视图控制器。这是它的工作原理。

我总是尽量避免创建一个新的视图控制器来支持不同的方向。相反,我设置代码来调整几何变化。我使用旧式调整大小的面具比使用AutoLayout更好,但是我使用了这两种方法。

答案 1 :(得分:0)

哦我的... performSegueWithIdentifier方法确实创建了另一个实例,即使它是同一个类。我找到了应用程序崩溃的根本原因。

在我的新项目中,当方向改变时,日志显示如下。当调用dismissViewControllerAnimated方法解除self时,新创建的实例将被释放。

self: <RootViewController: 0x7f99d1518890>, orientation: 3, isShowingLandscapeView: 0
show lanscape view
self: <RootViewController: 0x7f99d1518890>, orientation: 1, isShowingLandscapeView: 1
show portrait view
self: <RootViewController: 0x7f99d1727500>, orientation: 1, isShowingLandscapeView: 0
[RootViewController dealloc] [Line 35] !!!!!! dealloc instance: <RootViewController: 0x7f99d1727500>

但是,我的原始项目中的日志不会像上面那样显示...新创建的实例不是dealloc!所以它会崩溃,因为第二个实例是基于第二个故事UIViewController布局创建的,它不包含segue“go_landscape”。

self: <RootViewController: 0x7fc142818400>, orientation: 3, isShowingLandscapeView: 0
show landscape view
self: <RootViewController: 0x7fc142818400>, orientation: 1, isShowingLandscapeView: 1
show portrait view, self: <RootViewController: 0x7fc142818400>
self: <RootViewController: 0x7fc142200600>, orientation: 1, isShowingLandscapeView: 0
self: <RootViewController: 0x7fc142818400>, orientation: 3, isShowingLandscapeView: 0
show landscape view
self: <RootViewController: 0x7fc142200600>, orientation: 3, isShowingLandscapeView: 0
show landscape view
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<RootViewController: 0x7fc142200600>) has no segue with identifier 'go_landscape''

但为什么!???这两个项目都使用ARC机制并处理相同的代码。为什么新项目中的新实例将正常dealloc,但原始项目中的新实例将不会被dealloc!???????

必须解决此问题,否则在方向更改时会导致内存泄漏,因为它始终会创建新的垃圾实例。

答案 2 :(得分:0)

哦,我的上帝............我知道为什么原始项目中的新实例不会被dealloc。因为它会创建一个NSTimer对象并继续运行。所以实例永远不会被dealloc。好吧,这是我的错。 〜&#34;〜

- (void) startTimer {
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
                                             target:self
                                           selector:@selector(tick)
                                           userInfo:nil
                                            repeats:YES];
}