NavigationController 不会从函数调用 + swift 推送

Posted

技术标签:

【中文标题】NavigationController 不会从函数调用 + swift 推送【英文标题】:NavigationController wont push from function call + swift 【发布时间】:2016-10-12 02:27:25 【问题描述】:

我基本上是在尝试重新创建 whatsapp。我的 MainVC 有一个 TableView 可以显示所有当前的对话,并且有一个推送到 ChatVC 以显示整个对话。

当用户想要开始新的对话时,他们点击右上角的按钮,UserListVC 从底部出现并显示用户列表。

我的想法是,当用户单击用户时,“UsersListVC”会关闭(显示 mainVC)并调用一个函数来打开 ChatVC。但是,在 MainVC 关闭后,我无法成功调用函数。

请不要现在我没有推送任何数据我只是想让segues正常工作

MainVC.swift

func showChatVC() 

    print("FUnction called")
    let showChat = ChatVC()
    navigationController?.pushViewController(showChat, animated: false)


UsersListVC.swift

       func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
            dismiss(animated: true)  
                MainVC().showChatVC()
            
        

我尝试了几种不同的变体,但似乎根本无法在 MainVC 中调用该函数。我是不是太固执地想以这种方式做segues?我应该直接从 UsersListVC 转到 ChatVC

【问题讨论】:

什么是dismiss(animated: ) 在这一行 let showChat = ChatVC(),你正在创建一个新的聊天 VC 实例。相反,您需要访问您在情节提要中创建的“实例”。为此,请给 segue 一个标识符并调用 performSegueWithIdentifier 方法。 我尝试将 performSegue 调用放入我的函数 showChatVC 但当我在 NewMessageVC 中选择一行时,我什至无法调用该函数 showChatVC 或者我是否想到了如何实现这个错误,我应该在选择用户后从我的 NewMessageVC 转到聊天? MainVC().showChatVC() 创建MainVC 的新实例。这个新实例不在视图层次结构中,也不在导航控制器中。因此调用navigationController?.pushViewController(showChat, animated: false) 什么都不做,因为navigationControllernil。您需要检索对现有 MainVC 的引用,而不是创建新的。 【参考方案1】:

这里有很多答案,我想我应该使用委托模式为这些类型的问题添加我的解决方案。

通过委托,您可以从 UsersListVC 中调用 MainVC 中的函数,这使得与 ChatVC 的 segue 变得更加容易,并且在您将选定的用户传递给 ChatVC 时也会有所帮助。

要制作委托模式,您:

    创建一个协议来指定您的委托类必须实现的功能,通常我在委托类之上执行此操作,因此 MainVC。

    protocol UsersListDelegate: class 
    
        func newConversationCreated(withUser user: AnyObject)
    
    
    

    让您的委托类 (MainVC) 符合协议并实现所需的功能

    class MainVC: UIViewController, UsersListDelegate 
    
        func newConversationCreated(withUser user: AnyObject) 
    
            //I'll fill this in later in my answer
    
        
    
    
    

    在 UsersListVC 中创建一个变量来保存委托类

    class UsersListVC: UIViewController 
    
        weak var delegate: UsersListDelegate!
    
    
    

    当您从 MainVC 呈现 UsersList 时,将委托变量设置为 MainVC(self),例如,如果您转到 UsersList,则可以在准备 segue 时完成。

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    
        if let destination = segue.destination as? UsersListVC 
    
            destination.delegate = self
    
        
    
    
    

    或者如果你没有转场就展示它:

    func presentUsersList() 
    
        let userListsVC = UsersListVC()
        userListsVC.delegate = self
        self.present(userListsVC, animated: true)
    
    
    

您的委托模式现已完成。要在要创建新对话并关闭 UserListsVC 时调用委托函数,您可以这样做

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 

        delegate.newConversationCreated(withUser: /*Your User Object*/)

    

在 MainVC 中,您可以实现 newConversationCreated 函数:

关闭用户列表 创建 ChatVC 将用户传递给 ChatVC 介绍 ChatVC

例如

    func newConversationCreated(withUser user: AnyObject) 

        dismiss(animated: true)  

            let showChat = ChatVC()
            showChat.user = user
            navigationController?.pushViewController(showChat, animated: false)

        

    

附言从 MainVC 调用dismiss 可能看起来很奇怪,但这实际上是苹果的最佳实践(请参阅此question 中的答案以了解原因)。它会关闭用户列表,不用担心。

【讨论】:

【参考方案2】:

试试下面的代码

步骤 - 1

设置故事板标识符。

然后试试下面的代码

MainVC.swift

 func showChatVC() 

  let showChat = self.storyboard!.instantiateViewControllerWithIdentifier("ChatVc_ID") as! ChatVC
  self.navigationController?.pushViewController(showChat, animated: false)    

 

UsersListVC.swift

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    dismiss(animated: true)  
   let mainVC = self.storyboard!.instantiateViewControllerWithIdentifier("MainVC_ID") as! MainVC 
   mainVC.showChatVC()
         

【讨论】:

【参考方案3】:

尝试从您的 tableView's didSelectRow 方法发送操作,例如

UIApplication.sharedApplication().sendAction("showChatVC", to: nil, from: nil, forEvent: nil)

希望这会有所帮助。

【讨论】:

【参考方案4】:

我建议使用NotificationCenter:

MainVC 注册NewChatCreateNotification 喜欢:

NotificationCenter.default.addObserver(self, selector: #selector(autoNavigateToNewChat(_:)), name: NSNotification.Name(rawValue: "NewChatCreateNotification"), object: nil)

还是在MainVC,在autoNavigateToNewChat:方法里,推ChatVC

然后在您关闭UsersListVC后发布您的通知

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    //Use this dict to populate the userInfo of the notification, then you can use it when you push to ChatVC. 
    //You can obviously add more info to it like userId etc. as long as the data conforms to: [AnyHashable: Any]
    let dict = ["chatId" as NSString : <the selected chatId> as NSNumber]

    dismiss(animated: true)  
        NotificationCenter.default.post(name: Notification.Name(rawValue: "NewChatCreatedNotification"), object: self, userInfo: dict as [AnyHashable: Any])
    

【讨论】:

【参考方案5】:

以下内容应该适用于您的故事板设置。确保在情节提要中设置 segue 标识符。我在UsersListVC 中使用按钮而不是表格视图单元格。

import Foundation
import UIKit

internal enum SegueIdentifier: String 
    case showChat = "showChat"
    case showUserList = "showUserList"


internal final class MainVC: UIViewController 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == SegueIdentifier.showUserList.rawValue, let vc = segue.destination as? UsersListVC 
            vc.completion = 
                [weak self] in self?.performSegue(withIdentifier: SegueIdentifier.showChat.rawValue, sender: nil)
            
        
    


internal final class ChatVC: UIViewController 



internal final class UsersListVC: UIViewController 

    internal var completion: (() -> ())? = nil

    @IBAction func close(_ sender: UIButton) 
        dismiss(animated: true) 
            [weak self] in self?.completion?()
        
    

【讨论】:

【参考方案6】:

如果我没记错的话,您可以在您的关闭闭包中创建一个 MainVC 的新实例。

dismiss(animated: true)  
    MainVC().showChatVC()

由于这个新的 ViewController 从未在屏幕上显示,它也无法显示另一个 ViewController。

尝试获取对现有MainVC 的引用。

dismiss(animated: true)  [weak self] in
    if let mainVC = self?.presentingViewController as? MainVC 
        self?.mainVC.showChatVC()
    

否则尝试使用通知方法。

【讨论】:

以上是关于NavigationController 不会从函数调用 + swift 推送的主要内容,如果未能解决你的问题,请参考以下文章

Tab Bar 子 viewWillAppear 不会触发,添加 NavigationController 会给出两个导航栏

如果我在 iOS 8 中更改 topviewcontroller 的方向,则不会调用 NavigationController willRotateToInterfaceOrientation

添加NavigationController不会显示后退按钮

关闭没有 NavigationController 的推送视图控制器

双击 UITabBarItem 不会将 UITableView 滚动到顶部

在不影响导航栏的情况下更改 NavigationController 的内容视图宽度