尝试在控制器之间传递信息失败,但可以从 AppDelegate 到控制器

Posted

技术标签:

【中文标题】尝试在控制器之间传递信息失败,但可以从 AppDelegate 到控制器【英文标题】:Trying to pass information between controllers fails, yet works from AppDelegate to controller 【发布时间】:2017-05-23 16:48:03 【问题描述】:

我有两个 UIViewController,vc1 和 vc2。 vc1 嵌入在 UIViewController 中,UIViewController 嵌入在 UITabBarController 中,但 vc2 没有嵌入。

如何将信息从 vc2 传递到 vc1?用户执行操作后,数据被保存并且 vc2 简单地关闭,因此没有传递信息的 segue。显然我无法通过导航堆栈或 TabController 引用 vc1。

我可以保存到 AppDelegate,但我知道这不是一个好习惯。

这是我用来将信息从 AppDelegate 传递到 vc1 的代码,我在 vc2 中尝试过,但显然失败了。:

let tabBarController = window!.rootViewController as! UITabBarController
        if let tabBarViewControllers = tabBarController.viewControllers 
           let navPostViewController = tabBarViewControllers[0] as! UINavigationController

                let user = User(context: managedObjectContext)

                if user.userID  != nil 
                    print("User is loggedIn")
                    isUserLoggedIn = true
                 else 
                    print("User is not loggedIn")
                    isUserLoggedIn = false
                
                let postViewController = navPostViewController.topViewController as! PostViewController
                postViewController.managedObjectContext = managedObjectContext
        

【问题讨论】:

使用 AppDelegate 来保存这样的关键数据本质上没有任何问题。您还可以使用单例来保存您的数据模型。有些人会提倡写入 UserDefaults 来保存数据——但这似乎是登录状态等动态数据的错误方法。有些人肯定会反对这些方法 - 但您必须找到最适合您的方案的方法 VC1 是否存在 VC2(例如模态)?如果是这样,定义协议让 VC2 通知它的代理一些动作。然后,当 VC1 呈现 VC2 时,将 VC1 设置为 VC2 的代理。这比浏览视图控制器层次结构和/或使用应用程序委托(或任何其他对象)来保存通过 b/w VC2 和 VC1 传递的属性要好得多。 delegate 绝对是您场景中更好的方式,也是苹果推荐的方式。 @Rob 你的冠军。自从我开始开发以来,我一直在关注你。 这可能是 Passing Data between View Controllers 的副本。看到这个Swift answer 【参考方案1】:

首先,我从来没有养成使用 segue 传递信息的习惯。我会建议您在需要在两个对象之间传递数据时实现委托模式。它干净了很多。

例如,假设您想在 LoginViewControllerPostViewController 之间传递数据:

protocol LoginViewControllerDelegate:NSObjectProtocol
    func userDidLogin(data:String)



class LoginViewController:UIViewController 
    weak var delegate:LoginViewControllerDelegate?
    ...


    @IBAction func loginButtonPressed(sender:UIButton) 
        //Perform login logic here

        //If successful, tell the other controller or the 'delegate'
        self.delegate?.userDidLogin(data:"Some data....")
    



class PostViewController:UIViewController, LoginViewControllerDelegate 
    func userDidLogin(data:String) 
        print("Got data from login controller: \(data)")
    



//How you might use this
loginViewController.delegate = postViewController

要记住的一个警告是永远不要尝试在两个对象之间进行强引用,即不要让对象相互保持,否则会导致内存泄漏。

【讨论】:

除非它是一个class 协议,否则你不能使它成为weak。此外,如果它确实有 weak 引用,我不会将其设为隐式展开的可选项(否则,如果 delegatenil,应用程序将崩溃)。使用delegate?.userDidLogin(...) 语法更安全。例如。 gist.github.com/robertmryan/3d59608857f6b3797bf14dabb51a4a69 你说得对,我只是看了一下我的一些旧代码,协议确实必须从一个类扩展,就我而言,我只是扩展了NSObjectProtocol,所以我对其进行了编辑以反映这一点.还对隐式展开的可选进行了更新。 终于掌握了协议/委托的速度。这就像一个魅力。谢谢!

以上是关于尝试在控制器之间传递信息失败,但可以从 AppDelegate 到控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PageViewController 和 ViewController 之间传递数据?

面临从视图到控制器传递值的困难

如何在 Swift 中的视图控制器之间传递数据?

在 UIView 和 UIViewController 之间传递数据

如何通过委托将信息从键盘视图控制器传递到主视图控制器

iOS - 如何在通过手动 Segue 链接的两个视图控制器之间传递信息?