最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - Singleton for UIViewControler in Swift disallowed by compiler? - Stack Overflow

programmeradmin3浏览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()
   
}

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()
   
}
Share Improve this question asked 17 hours ago user6631314user6631314 1,9661 gold badge18 silver badges55 bronze badges 6
  • 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. – Paulw11 Commented 16 hours ago
  • 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() – Paulw11 Commented 16 hours ago
  • @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. – Fattie Commented 16 hours ago
  • 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. – Paulw11 Commented 16 hours ago
  • I totally agree with Paul, but I’m voting to close this question because, comments added to the original question were extremely opinionated, and potentially suggest bad advice. These do digress from the actual problem of the OP. Unfortunately, this makes it difficult for the OP to get a fair and reasonable answer. – CouchDeveloper Commented 6 hours ago
 |  Show 1 more comment

2 Answers 2

Reset to default 0

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.

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.)

发布评论

评论列表(0)

  1. 暂无评论