简体   繁体   English

如何使数据对所有视图控制器可见?

[英]How to make data visible for all view controllers?

Let's consider the following case: 让我们考虑以下情况:

I have a tab bar application where tapping each tab bar item takes user to other view that is handled by different view controller(typical pattern). 我有一个选项卡栏应用程序,在其中点击每个选项卡栏项会将用户带到其他视图,该视图由不同的视图控制器(典型模式)处理。

In one of my controllers I have method that downloads the important data and I want them to be global for whole application. 在我的一个控制器中,我有一种方法可以下载重要数据,并且希望它们对于整个应用程序是全局的。 What design pattern should I use? 我应该使用哪种设计模式?

One way to do that is to store this data using persistence such as core data, but is it the only way to make data visible for all view controllers? 一种方法是使用持久性(例如核心数据)存储此数据,但这是使数据对所有视图控制器可见的唯一方法吗? Maybe app delegate is able to perform such actions? 也许应用程序委托能够执行此类操作?

How in general you solve such situation where you have some data or variable which should be visible for all view controllers in your project? 通常,如何解决这种情况,即您拥有一些数据或变量,这些数据或变量对于项目中的所有视图控制器都是可见的?

Note that I'm not asking about persisting data across launches of the app, I just wonder how to make some data global in terms of the whole project. 请注意,我并不是要在应用程序的各个启动之间持久保存数据,我只是想知道如何在整个项目中使某些数据具有全局性。

Dont (emphasize DON'T) use following: 不要(强调不要)使用以下内容:

  • Singletons 单身
  • AppDelegate (just another Singleton) AppDelegate(只是另一个Singleton)
  • NSUserDefaults NSUserDefaults的

Rather Don't: 宁可不要:

  • Core Data 核心数据

Do: 做:

  • pass in either during instantiation or via properties 在实例化期间或通过属性传递

Why? 为什么?

The DON'Ts messes up your memory 不要弄乱你的记忆
the Rather Don't messes with several principals of SOLID . 宁可不要弄乱SOLID的几个原理。

How would you do it correctly: 您将如何正确地做到这一点:

  • Create a base view controller that has a property that takes your data, make all your view controller inherit from it. 创建一个具有获取数据属性的基本视图控制器,使所有视图控制器都从其继承。

  • subclass UITabBarController 子类UITabBarController

  • if a new view controller is selected, set the data to the view controller 如果选择了新的视图控制器,则将数据设置为视图控制器

the implementation is a bit tricky, this is from a real world app 实施有些棘手,这是来自真实世界的应用程序

class ContentTabBarController : UITabBarController {

    private var kvoSelectedViewControllerContext: UInt8 = 1

    required init(coder aDecoder: NSCoder) {


        self.addObserver(self, forKeyPath: "selectedViewController", options: .New | .Old | .Initial , context: &kvoSelectedViewControllerContext)
    }

    deinit{
        self.removeObserver(self, forKeyPath: "selectedViewController")
    }

    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        if context == &kvoSelectedViewControllerContext {
            var targetVC : UIViewController?

            if let viewController = change["new"] as? UIViewController{
                if let oldViewController = change["old"] as? UIViewController{
                    if viewController != oldViewController {
                        targetVC = viewController
                    }
                }
            } else {
                targetVC = self.viewControllers![0] as? UIViewController
            }
            self.configureTargetViewController(targetVC)
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.navigationBar.translucent = false
    }

    func configureTargetViewController(viewController: UIViewController?){

        //setup data
    }
}

How does the tab bar controller get the data. 标签栏控制器如何获取数据。

Well, that is up to you. 好吧,这取决于您。 It could fetch core data, it could actually pass a fetching manager as data. 它可以获取核心数据,实际上可以通过获取管理器作为数据。 It could read from disc or network. 它可以从光盘或网络读取。 But for a sane design it should not do it itself but use another class for it. 但是对于一个理智的设计,它不应该自己做,而要使用另一个类。 and an instance of this fetcher class should be set from outside the tab bar controller, ie from the App Delegate. 并且应该从选项卡栏控制器外部(即从App Delegate)设置此fetcher类的实例。

One easy way would be to make a struct and make it hold variables. 一种简单的方法是构造一个结构并使其包含变量。 Then, you can edit it anytime you would want to. 然后,您可以随时编辑它。 For example: 例如:

struct Variables {
   static var number = 4
}

Then you can edit the data inside Variables in any view controller you want by doing this code. 然后,您可以通过执行以下代码在所需的任何视图控制器中的“变量”中编辑数据。

Variables.number = 6 //or any other number you want

A cleaner and efficient, although not necessarily different, way to do this is to create a singleton class , eg AppData , which you can access in a variety of ways, and which would be available to all your other classes. 做到这一点的一种更干净高效的方法(虽然不一定是不同的)是创建一个单例类 ,例如AppData ,您可以通过多种方式访问​​它,并且该类对于所有其他类都可用。 It has the benefit of separating your app-specific stuff from the app delegate stuff. 它具有将特定于应用程序的内容与应用程序委托的内容分开的好处。 You might define the class this way: 您可以这样定义类:

@interface AppData : NSObject

// Perhaps you'll declare some class methods here & objects...

@end

you can define ivars for the AppData class, and then manage a singleton instance of AppData. 您可以为AppData类定义ivars,然后管理AppData的单例实例。 Use a class method, eg +sharedInstance , to get a handle to the singleton on which you could then call mehods. 使用类方法,例如+ sharedInstance ,获取单例的句柄,然后可以在其上调用方法。 For example, 例如,

[[AppData sharedInstance] someMethod:myArgument];

Your implementation of +sharedInstance can be where you manage the actual creation of the singleton, which the method ultimately returns. 您可以在+ sharedInstance的实现中管理单例的实际创建,该方法最终将返回该单例。

Singleton pattern can be useful here. 单例模式在这里可能很有用。 In Swift it can be created something like this: 在Swift中,可以这样创建:

class SomeManager {
    static let sharedInstance = SomeManager()

    var someData: NSData?
}

And accessing it later in your view controllers as SomeManager.sharedInstance.someData 稍后在您的视图控制器中作为SomeManager.sharedInstance.someData访问它

More info about singletons in Swift and a bit in Objective-C here 有关Swift中单例的更多信息以及Objective-C的更多信息,请点击此处

Try this simple method, 试试这个简单的方法,

1) Create a variable in appdelegate.swift that could be visible to all viewcontroller. 1)在appdelegate.swift中创建一个对所有viewcontroller都可见的变量。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

 ...
 ...
 var Check:String!="" // to pass string
 ...
 ...    
}

2) Create appdelegate instance in any viewcontroller 2)在任何viewcontroller中创建appdelegate实例

viewcontroller1.swift viewcontroller1.swift

import UIKit

class ViewController: UIViewController {

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

   ...
   ...

    override func viewDidLoad() {
        super.viewDidLoad()
        ...
    var tmp = "\(appDelegate.Check)"
    appDelegate.Check="Modified"
    }
}

Viewcontroller2.swift Viewcontroller2.swift

import UIKit

    class ViewController: UIViewController {

        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

       ...
       ...

        override func viewDidLoad() {
            super.viewDidLoad()
            ...
        var getdata = "\(appDelegate.Check)"
        println("Check data : \(getdata)") // Output : Check data : Modified
        }
    }

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

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