Ios 使用标识符展开segue/PerformsgueWithIdentifier:问题

Ios 使用标识符展开segue/PerformsgueWithIdentifier:问题,ios,objective-c,xcode,Ios,Objective C,Xcode,在我的应用程序中,有一个聊天服务。当用户想要给某人发送新消息时,他按下“new chat”(新建聊天),屏幕上会显示一个表视图控制器,用于从好友列表中进行选择。我正在使用“展开”分段,以便返回到上一个视图控制器,并在两个视图控制器之间共享数据(主要是数据将是与之聊天的朋友)。放松segue工作得很好,但是在我的应用程序中,当用户返回主VC时,我会启动一个新segue,以便直接转到另一个VC,用户可以在那里聊天;这不管用。所有的区段都连接得很好,我在每个角落都尝试了NsLog,它正在进入那里,甚至

在我的应用程序中,有一个聊天服务。当用户想要给某人发送新消息时,他按下“new chat”(新建聊天),屏幕上会显示一个表视图控制器,用于从好友列表中进行选择。我正在使用“展开”分段,以便返回到上一个视图控制器,并在两个视图控制器之间共享数据(主要是数据将是与之聊天的朋友)。放松segue工作得很好,但是在我的应用程序中,当用户返回主VC时,我会启动一个新segue,以便直接转到另一个VC,用户可以在那里聊天;这不管用。所有的区段都连接得很好,我在每个角落都尝试了NsLog,它正在进入那里,甚至prepareForSegue:也正在被访问。我试着放了一个NsTimer,认为可能有一些技术冲突,但它不起作用。我将聊天室VC的segue更改为模态,现在它给了我以下错误:

警告:尝试显示其视图不在窗口层次结构中的对象

我可以通过其他方式访问这个VC,它是在层次结构中。我的问题是:会出什么问题?展开分段是否会改变windows层次结构

图片:


为了更直观地呈现问题,我所说的主要VC位于左下角,连接到导航视图控制器。当用户按下new chat时,右上角的两个VC显示(一个用于在朋友或组之间进行选择,另一个用于显示朋友/组)。所以,当一个朋友被选中,比如说从右上角的VC,我应该放松到主VC。正如你从主VC中看到的,还有其他的环节。如果我执行“放松”顺序,它们中的任何一个都可以工作,如果我正常操作,它们也可以工作。

好的,解决了这个问题,问题是视图还没有出现,我不得不通过以下方式延迟过程:

[self performSelector:@selector(fireNewConv) withObject:nil afterDelay:1];

然而,有趣的是,我尝试通过NSTimer进行延迟,但没有成功。

不要使用计时器或延迟来尝试和预测何时可能存在视图

相反,使用如下调用:-(void)dismissViewControllerAnimated:(BOOL)标志完成:(void(^)(void))完成

当你回到主VC时,完成模块会让你知道。或者,查看与segue关联的各种调用,以便准确地知道何时可以在新窗口上执行操作


如果所有其他操作都失败,则始终会出现UIViewController ViewDid。

它不起作用并且给您带来错误的原因是,事情没有按照您认为的顺序发生

当展开发生时,可见的视图尚未被取消,因此您试图对实际上不在该层次结构中的视图执行一个序列,如错误所述。例如,在最终视图中放置NSLog语句,然后在主视图控制器中的unwind方法中,您可以看到以下内容:

2013-11-27 14:51:10.848 testUnwindProj[2216:70b] Unwind
2013-11-27 14:51:10.849 testUnwindProj[2216:70b] Will Appear
2013-11-27 14:51:11.361 testUnwindProj[2216:70b] View Did Disappear
因此,将调用主视图中的展开,视图将出现(主视图控制器),然后取消可见视图。这可能是一个简单的解决方案:

@interface ViewController () {
    BOOL _unwindExecuted;
}

@end

@implementation ViewController

- (void)viewWillAppear:(BOOL)animated
{
    NSLog(@"Will Appear");
    if (_unwindExecuted) {
        _unwindExecuted = NO;
        [self performSegueWithIdentifier:@"afterunwind" sender:self];
    }
}

- (IBAction)unwind:(UIStoryboardSegue *)segue
{
    NSLog(@"Unwind");
    _unwindExecuted = YES;
}

这是处理展开的视图控制器的常见问题,因为在展开期间,该视图控制器可能不在窗口层次结构中

为了解决这个问题,我添加了一个属性
segueIdentifierToUnwindTo
,以协调展开

这与JAManfredi的答案类似,但将其扩展为能够切换到任何视图控制器

@interface FirstViewController ()
// Use this to coordinate unwind
@property (nonatomic, strong) NSString *segueIdentifierToUnwindTo;
@end

@implementation FirstViewController
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];   
    // Handle unwind
    if (_segueIdentifierToUnwindTo) {
        [self performSegueWithIdentifier:_segueIdentifierToUnwindTo sender:self];
        self.segueIdentifierToUnwindTo = nil;   // reset
        return;
    }
    // Any other code..
}

// Example of an unwind segue "gotoLogin"
- (IBAction)gotoLogin:(UIStoryboardSegue*)sender {
    // Don't perform segue directly here, because in unwind, this view is not in window hierarchy yet!
    // [self performSegueWithIdentifier:@"Login" sender:self];
    self.segueIdentifierToUnwindTo = @"Login";
}
@end

我还在我的博客上分享了如何与
FirstViewController
一起使用展开段:

考虑到我们看不到您的故事板或代码,这里的纯猜测,但很可能您试图从展开段已取消的视图中呈现视图控制器,你能给我们看一些代码或什么吗?@JAManfredi好的,我添加了一张图片和一个解释。我想代码是最小的,不会有任何区别。希望这是清楚的。这不是一个答案,而是对OP答案的评论。这是最糟糕的实现方式。您只是在猜测展开动画何时结束。正如@Ike正确地指出的,这就是
viewdide:
的目的;使用实例变量来检测视图的这种外观是否是触发下一个序列的信号。更好的解决方案可能是实现
segueforunwinding到viewcontroller:fromViewController:identifier:
,它允许您在代码中完全控制整个退绕过程。或者,只是手动放卷(不使用放卷序列)。不要这样做。使用完成块。好的!谢谢你的洞察力!我真的很感激!我没有想到它会被任务压得有点喘不过气来。我必须将viewwillbeen更改为viewdidabeen,以使我的代码正常工作,但感谢您的帮助。就是这样!当然,这比用硬编码的时间进行调度要好得多