0

I have a UIViewController class with a variable shared that allows other classes to reach it as a singleton. However, the compiler (with Main Thread Checker enabled in Scheme Settings) is flagging the variable in purple with the warning:

-[UIViewController init] must be used from main thread only

I was not aware that merely including a shared variable to initiate the View Controller as a singleton is not allowed. I guess it makes sense insofar as when you initiate the VC it initiates the life cycle and views. But would appreciate someone confirming this and/or further shedding light on what is going on.

Here is the code that triggers the warning:

@objcMembers class MyVC : UIViewController, UITableViewDelegate, UITableViewDataSource,UITextViewDelegate {
  
    static var shared = MyVC()
   
}
4
  • 1
    Singletons, in general, are an anti-pattern, but can be useful. a UIViewController singleton is definitely not a pattern I would be following. While a "root" view controller may indeed be in the view controller hierarchy for the lifetime of your app, it is still probably better to obtain the reference dynamically via, say, the rootViewController property of your window or scene, than to use a singleton. Your question also implies that you are using a view controller where a data model would be more appropriate. Commented Feb 9 at 23:18
  • 1
    And, yes, as HangarRash pointed out your warning is because your first access of MyVC.shared is occurring from a non-main queue context. Since any operation that actually resulted in the view controller being added to the view hierarchy would have to be on the main queue, this would also indicate that MyVC.shared is not actually in the view hierarchy. You should be using one of the designated initialisers for a UIViewController, not init() Commented Feb 9 at 23:21
  • @Paulw11 singletons are the absolute basis of all phone programming. Literally everything is a singleton. (Notably say ... "the app" :). ). It's absurd to declare that you don't like singletons, in an iOS milieu. Every service you make (APIs whatever) is done as a singleton. Commented Feb 9 at 23:36
  • 1
    That's not true. Certainly UIKit and a lot of Apple frameworks do provide singletons, but the model in newer frameworks and SwiftUI is moving away from singletons and into a DI model; e.g. before iPadOS supported multiple windows you could rely on the singleton Window, but now you should access the current window scene. Singletons make testing harder and lead to undesirable class coupling. I say that they can be useful and, yes, in some cases I will still use them, but I try not to. And a singleton UIViewController is definitely a bad idea. Commented Feb 10 at 0:03

2 Answers 2

2

Your question is making the assumption that you are getting a compiler warning due to the use of a singleton view controller. This is not the case.

The warning about calling UIViewController init on a non-main queue is actually a runtime warning. Note that the scheme setting "Main Thread Checker" is under the "Runtime API Checking" section of the Diagnostics tab. Note that compiler warning show in Xcode as yellow triangles. Runtime warnings, such as this, appear as purple triangles.

The warning is not due to the code you posted. It is due to some other code that is making the first call to MyVC.shared from a non-main queue. The solution is to find the offending code and ensure, like all UI code, that it is only called from the main queue.

Put a breakpoint on the line static var shared = MyVC() and run your app to see which code calls it first. You should see from the stack trace shown at that point that it is on something other than Thread 0.

Sign up to request clarification or add additional context in comments.

1 Comment

I am deliberately not covering the pros and cons of the use of a singleton VC in my answer. I am answering the question being asked. Let's avoid opinions on the matter and focus on the specifics of the question.
-3

A view controller can't be a singleton, that is meaningless.

You simply do this

class ChartView:  UIViewController {

    static var current: ChartView?

set it to self in viewDidLoad

Access it from elsewhere as ChartView.current?.

if your app is broken and you accidentally make two or more of the ChartView screens (which can happen) it's just your fault, don't do that.

That is generally poor practice, but that's how you do what you're trying to do.

(Generally you never do this - other than for the baseboard of the app, which is how 99% of apps work.)

3 Comments

A view controller can be a singleton. I'm not saying it should be done, but it can be.
A VC can't be a singleton. You can always create one from storyboard.
You keep stating that a VC can't be a singleton without stating why. I know for a fact that a VC can be a singleton because I did it once in a past project. Again, I don't recommend it but it can be done. You should update your answer with your explanation of why you think it "can't" be a singleton.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.