Create singleton of a viewcontroller in swift 3
Asked Answered
C

3

6

I know how to create singleton class in swift. The best and easy way to create singleton class is the following:

class Singleton {
    static let sharedInstance = Singleton()
}

But I don't need singleton for any normal class. I need to create singleton for a viewcontroller class. So I'm using this code create singleton

class AViewController:UIViewController {

    static let sharedInstance = AViewController()

    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

}

it gives me error near AViewController()

Missing argument for parameter 'coder' in call

Looks like it want me to initialize with init(coder: NSCoder). But what parameter or value should I pass through the coder?

Cambric answered 14/12, 2016 at 7:0 Comment(17)
have you checked with class Singleton : NSObject this?Claret
Why didn't you put the problematic code in your question?Sudanic
required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }Barnaby
'required public init?(coder aDecoder: NSCoder){ super.init(coder: aDecoder) }' Add this in your codeFredric
@Sudanic : Please see my updated question.Cambric
@BhavinRamani : I already implemented this.Cambric
Do you use storyboard?Selfappointed
View controllers are not generally good candidates for singletons. If you really want to do this, we'd probably need to know more about how the view hierarchy for this view controller is created (a scene in a storyboard? NIB? programmatically created?). But, if you're interested, you might want to explain why you want to use a singleton and we might be able to suggest better patterns.Karttikeya
@AhmadF : Yes. The viewcontroller is in storyboard.Cambric
1) Why would you want a singleton view controller? 2) Please post more relevant code. Do you have any init methods? At least show the method signatures.Sudanic
@Karttikeya : I want to use this viewcontroller as a sidepanel. And yes the viewcontroller is in storyboard. I have created singleton for viewcontroller in Objective C. Now I want to convert it to swift.Cambric
@Sudanic : I have a init method. Please see the updated question.Cambric
@Cambric If you had already implemented required init method, then why are you asking what parameter or value should I pass through the coder?Barnaby
@BhavinRamani : Because I implemented init? (coder aDecoder: NSCoder) and this want me to pass a coder value.Cambric
And this side panel, itself, has its own scene in the storyboard? And just because this is a side panel, that doesn't suggest that a singleton is a good pattern, even if that's what you were doing before...Karttikeya
Possible duplicate of Using the Swift SingletonAbroad
@FedericoMalagoni : Your link doesn't explain you to create singleton from viewcontroller. Remove duplicate flag from my question.Cambric
K
14

If you really wanted to have singleton for a view controller corresponding to some scene, you'd probably do something like:

class SecondViewController: UIViewController {

    static let shared = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Foo")

}

In this example, the storyboard was Main.storyboard and the storyboard identifier for the scene in question was Foo. Obviously, replace those values for whatever was appropriate in your case.

Then your other view controller that was invoking this could do something like:

@IBAction func didTapButton(_ sender: Any) {
    let controller = SecondViewController.shared
    show(controller, sender: self)
}

I wouldn't recommend singletons for view controllers. View controllers (and their views) should be created when needed and be allowed to be deallocated when they're dismissed. And you're losing many storyboard benefits (by which you see the logical flow between scenes with segues between them). And, if you use this view controller in different contexts, you're inviting problems stemming from the view controller hierarchy falling out of sync with the view hierarchy. I really would discourage you from using singletons for view controllers.

But if you were going to do it, you could do something like that...

Karttikeya answered 14/12, 2016 at 7:17 Comment(7)
I need to have same controller/view in 3 tabs of UITabBarController. Should I use singleton? or seperate instace for each would be recommended? Please share your suggestion for this case.Diogenes
First, I should say that I think view controllers are poor use case for singletons in general. Second, if you have three tabs, I'm assuming there's something different about each (e.g. different data even if the class for the view controller is the same), so I'd definitely suggest separate instances for each.Karttikeya
Ok..thank you for the response and yeah..I had to go with separate instancesDiogenes
@Rob: I used your suggestion and it works perfectly fine. My use case is that I am going to the ViewController A where I wait for the connection to be established. Meanwhile I can go back or change to another ViewController. So when I come back to A I will have a new instance and all new subscriptions to my relays. So I thought about singleton for my VC. I don't see any misbehaviour now but I wanna avoid it. My app is gonna be on Apple store so I don't want them to reject it because of not following the standards. So do you have any suggestion?Pileous
@Pileous 1. Apple doesn’t care about the design patterns you use in your code. They only care about what you do, not how you do it. 2. If you want to keep VC A alive, that doesn’t necessarily mean that you need to jump to singleton pattern. You just need to keep a reference to it. 3. If you’re trying to keep ongoing connection request going, this code doesn’t belong in the view controller anyway, so the question isn’t really keeping VC A alive, but rather network layer. That’s how I’d do it. But, again, Apple doesn’t care about code elegance and beautiful architectures, so do whatever you want.Karttikeya
@Rob: The network layer is separate and it is the one which oversees the connection. The state of VC A changes according to the connection status. So, if VC A shows a view for the connecting state, when the connection changes to the connected state, it shows another view. This is done with the relays, so if I go back and forth, then I have more than one subscription to those relays. That's what I want to avoid.Pileous
Totally agree with Rob. Can't the VC listen to the connection status? See developer.apple.com/library/archive/samplecode/Reachability/… & medium.com/@dkw5877/reachability-in-ios-172fc3709a37Gaskill
S
3

Try to do:

AppDelegate:

Add a reference to the ViewController, so you can access it globally, like so:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    private var viewController: ViewController?

    func getViewController() -> ViewController {
        if viewController == nil {
            // make sure that the name of the storyboard is "Main"
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            // make sure that you named the viewcontroller in storyboard (Storyboard ID), it is the identifier
            viewController = storyboard.instantiateViewController(withIdentifier: "ViewControllerStoryboardID") as! ViewController
        }

        return viewController!
    }


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // ....
}

AnotherViewController (Usage):

Now you can access it via "AppDelegate", like so:

class AnotherViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()


        let appDelegate = UIApplication.shared.delegate as! AppDelegate

        let vc = appDelegate.getViewController()
    }

    // ...
}

Hope this helped.

Selfappointed answered 14/12, 2016 at 7:21 Comment(0)
E
2

I would recommend something like:

enter image description here

Eloign answered 25/1, 2021 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.