performSegue 并不总是转换,但 prepare(for:sender) 总是被调用

Posted

技术标签:

【中文标题】performSegue 并不总是转换,但 prepare(for:sender) 总是被调用【英文标题】:performSegue doesn't always transition, but prepare(for:sender) always called 【发布时间】:2017-06-22 19:20:25 【问题描述】:

performSegue 被调用时,我的应用程序并不总是切换到下一个视图控制器。但是,它总是会立即执行prepare(for:sender)

有什么原因导致performSegue 在没有硬错误的情况下无法工作(并且仍然执行prepareForSegue)? 是否存在我需要检查的源视图控制器应该处于的某种状态? 如果我延迟 10 秒(通过 asyncAfter),就会发生转场。

场景

我正在尝试为新功能(集成到 Spotlight 搜索)重新调整工作 segue。如果应用程序留在详细视图中,则不会在我的 iPhone 上发生转换。 (该应用有一个 UISplitViewController 作为它的根视图控制器。)

但是,当

    我在 iPad 上进行测试 - 即同时显示主视图和详细视图时。 当我将应用程序留在主视图时,我在 iPhone 上进行测试。

当我从详细信息屏幕测试我的 iPhone 见下面的代码:

    详细信息屏幕消失(根据popToRootViewController) 显示主视图,并突出显示正确的行(包括显示“进入主视图”的 NSLog) 函数执行,包括prepare(for:sender),但从未显示详细视图。

此时,我可以点击相应的行,转场按预期发生 - 即 tableView(:didSelectRowAt:) 调用 performSegue

更多细节

Swift 3.0 和 ios 10

应用程序有一个 UISplitViewController 作为它的 rootViewController。主视图是一个带有食谱列表的 tableView。详细视图是一个 tableView,列出了所选配方的成分。 segue 从配方行选择过渡到其成分表。

我放入一个新功能:将食谱放入聚光灯,使用户可以搜索它们并在选择时,从主视图中选择配方,并在详细视图中显示其成分。

现在我正在尝试通过 appDelegate 的 application(:continue:restorationHandler) 实现 Spotlight 搜索集成:

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool 

    guard userActivity.activityType == CSSearchableItemActionType,
    let userInfo = userActivity.userInfo,
    let id = userInfo[CSSearchableItemActivityIdentifier] as? String
        else 
            return false
    

    // The id is a unique identifier for recipe.
    if let inputRecipe = Recipe.getBy(uuid: id, moc: self.managedObjectContext) 

        let root = self.window?.rootViewController as! UISplitViewController
        let nav = root.viewControllers[0] as! UINavigationController

        // If this is a navigation controller, then detail is being shown
        if (nav.topViewController as? UINavigationController) != nil 
            NSLog("Should be a detail view")
            nav.popToRootViewController(animated: true)   
        

        if let masterVC = nav.topViewController as? RecipeMasterVC 
            NSLog("Into the master")
            masterVC.selectTableRowAt(recipe: inputRecipe)
        
    
    return true

在 RecipeMasterVC 中,我将此代码添加到 segue

func selectTableRowAt(recipe: Recipe)

    let indexPath = self.fetchedResultsController.indexPath(forObject: recipe)

    self.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .top)
    DispatchQueue.main.async 
        self.performSegue(withIdentifier: seguesEnum.RecipeDetail.rawValue, sender: recipe)
    

【问题讨论】:

主视图控制器可能尚未加载。视图控制器完全有可能存在 - 即已调用 init() 以便拆分视图控制器引用它,但尚未调用 viewDidLoad()。尝试在 viewDidLoad() 中添加一些调试代码或检查 selectTableRow 中的 isViewLoaded 方法以跟踪主视图何时实际加载。 @Dale - 在DispatchperformSegue 之前,self.isViewLoaded 的值为真。 我自己的应用程序中也有类似的场景,没有使用 segue,但仍然使用拆分视图。当我检查代码时,我发现我必须添加 200 毫秒的延迟才能使其工作。从来没有找到根本原因,但没有延迟,即使已经显示详细信息屏幕,即使调度异步也不起作用 会的。谢谢 【参考方案1】:

我自己的应用程序中也有类似的情况,没有使用 segue,但仍然使用拆分视图。当我检查代码时,我发现我必须添加 200 毫秒的延迟才能使其工作。从来没有找到根本原因,但没有延迟,即使已经显示详细信息屏幕,即使调度异步也不起作用

【讨论】:

以上是关于performSegue 并不总是转换,但 prepare(for:sender) 总是被调用的主要内容,如果未能解决你的问题,请参考以下文章

为啥 constexpr 隐式转换并不总是有效?

VLC 命令行转换并不总是有效

使用 performSegue 显示 navigationController

Swift 3:PerformSegue WithIdentifier 不显示视图控制器,没有错误

Pyside2如何打开对话框但并不总是在顶部

Flash NetStream 接收数据但并不总是显示它