简体   繁体   English

如何从AppDelegate.swift访问不是根视图控制器的视图控制器?

[英]How to access a view controller that is not the root view controller from AppDelegate.swift?

I think this is a beginner question. 我认为这是一个初学者的问题。 I currently have two view controllers: 我目前有两个视图控制器:

class MainViewController: UIViewController {
    var markersToDelete = Marker()
    func deleteMarkers() {}
}

class MapViewController: UIViewController {
    var markersToDelete = Marker()
    func deleteMarkers() {}
}

The MapViewController is instantiated with a modal segue in the storyboard. MapViewController在情节提要中通过模式选择实例化。 I know that I can access MainViewController in AppDelegate.swift with this code: 我知道我可以使用以下代码访问AppDelegate.swift MainViewController

var mainViewController = self.window!.rootViewController as! MainViewController

How can I do the same thing with MapViewController ? 如何使用MapViewController做同样的事情?

EDIT 编辑

Based on the comments below I am updating this to include more detail. 基于以下评论,我将对此进行更新以包括更多详细信息。 Here is what I am trying to accomplish: 这是我要完成的工作:

I have IBActions in both view controllers that appends Marker items to the 我在两个视图控制器中都有IBAction,它们将Marker项目附加到
markersToDelete array. markersToDelete数组。 The method deleteMarkers is used to find the corresponding items in the Core Data persistent store and delete them; deleteMarkers方法用于在Core Data持久性存储中找到相应的项目并将其删除; it is called by AppDelegate when applicationDidEnterBackground or when applicationWillTerminate. 当applicationDidEnterBackground或applicationWillTerminate时,由AppDelegate调用。

This is the reason why I want to access both view controllers from app delegate. 这就是为什么我要从应用程序委托访问两个视图控制器的原因。 I am starting to think there could be a better way to do this. 我开始认为可能会有更好的方法来做到这一点。

Some other answers suggest ways of insantiating the controller, but they seem incorrect since you mentioned the controller is instantiated through a segue. 其他一些答案提出了使控制器失效的方法,但是由于您提到控制器是通过segue实例化的,因此它们似乎是不正确的。 There is no straight forward way of doing what you want, and for a good reason, it should be hard to access things from unrelated code. 没有任何直接的方法可以执行您想要的操作,并且有一个很好的理由,应该很难从无关的代码中访问内容。 In your very simple example, this code would work, given the controllers have already been presented: 在您的非常简单的示例中,假定已经介绍了控制器,则此代码将起作用:

var mainViewController = self.window!.rootViewController as! MainViewController
let mapViewController  = mainViewController.presentedViewController

But I would strongly discourage this type of code inside AppDelegate , it makes a lot of assumptions and will break easily if your navigation structure changes. 但是我强烈不建议在AppDelegate这种类型的代码,它会做出很多假设,并且如果导航结构发生变化,则很容易破坏。 Be more specific about what you're trying to achieve and you may get answers that lead you to a better architecture. 更具体地说明您要实现的目标,您可能会得到答案,从而使您获得更好的体系结构。

EDIT 编辑

Given the new information provided by the asker, this is a proposed solution to the more specific problem: 考虑到问询者提供的新信息,这是针对更具体问题的建议解决方案:

I understand you have Marker objects in your Core Data context, and you wish to batch delete some of them. 我了解您在Core Data上下文中有Marker对象,并且希望批量删除其中一些对象。 What about adding a bool property to Marker class, and setting it to true for the objects you wish to delete. 要将一个bool属性添加到Marker类,然后将要删除的对象设置为true,该怎么办? Then, in AppDelegate , you fetch the markers which have that property set to true, and delete them. 然后,在AppDelegate ,获取将属性设置为true的标记,然后将其删除。 This way you don't need to mantain an array, and there is no coupling between classes. 这样,您不需要维护数组,并且类之间没有耦合。

You can access your map controller by calling it's storyboard ID, which you'll need to set in Storyboard. 您可以通过调用情节提要ID来访问地图控制器,您需要在情节提要中对其进行设置。 Then just do: 然后做:

let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
var mapViewController = storyboard. instantiateViewControllerWithIdentifier("storyboardID") as! MapViewController

You need to set storyboard ID to your mapViewController . 您需要将Storyboard ID设置为mapViewController Then You can access it from appDelegate . 然后,您可以从appDelegate访问它。

let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main",bundle: nil)
var destViewController : UIViewController
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("YourViewController") as! UIViewController

You should start by encapsulating your code which is responsible for interaction with CoreData framework API. 您应该先封装负责与CoreData框架API交互的代码。

Create a singleton class like below and use this class only for insertion/deletion/update operations. 创建一个如下所示的单例类,并将该类仅用于插入/删除/更新操作。 This way will ensure loose coupling among your view controllers . 这样可以确保视图控制器之间的松散耦合。

You can get reference to the sharedInstance of DataManager in any class. 您可以在任何类中sharedInstanceDataManagersharedInstance的引用。 . Using sharedInstance you can call methods related to your Database operations. 使用sharedInstance可以调用与数据库操作相关的方法。

class DataManager {
        class var sharedInstance : DataManager {
            struct Singleton {
                static let instance = DataManager()
            }
            return Singleton.instance
    }
    func deleteMarkers() {
    //Your logic here
}
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM