Xcode 9 更新 Swift,紫色警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46490140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 10:20:24  来源:igfitidea点击:

Xcode 9 update Swift, purple warning

iosswiftxcodeswift4xcode9

提问by KirillC

Not sure why after updating to Xcode 9 my project (originally created in Swift 3) is showing purple warnings: UITextField.text must be used from main thread only

不知道为什么在更新到 Xcode 9 后,我的项目(最初在 Swift 3 中创建)显示紫色警告: UITextField.text must be used from main thread only

I'm only checking in If statement if text field is empty... attaching screenshot.

如果文本字段为空,我只检查 If 语句...附上屏幕截图。

enter image description here

在此处输入图片说明

回答by JeremyP

The login manager is running your closure on a thread other than the main thread and you can't use user interface elements off the main thread.

登录管理器在主线程以外的线程上运行您的闭包,您不能在主线程之外使用用户界面元素。

Others have said that it's OK just to read UI properties on side threads and they are probably right, but there is no absolute guarantee of it and, personally, I would heed the warnings. For example, accessing those properties could have side effects. Perhaps their values are cached somewhere and the main thread is in the process of updating or deleting the property just when you want to access it.

其他人说只读取侧线程上的 UI 属性是可以的,他们可能是对的,但没有绝对的保证,就我个人而言,我会注意警告。例如,访问这些属性可能会产生副作用。也许它们的值被缓存在某个地方,而主线程正在更新或删除属性的过程中,就在您想要访问它时。

The proper way to silence the warnings is to execute your cloasure on the main thread e.g.

使警告静音的正确方法是在主线程上执行您的闭包,例如

LoginManager.checkLoginStatus {
    isLoggedIn in

    DispatchQueue.main.async {

        // Do all your UI stuff here

    }
 }

This way the thread that runs the closure does nothing except schedules the code to run in the main queue which always runs on the main thread.

这样,运行闭包的线程除了将代码安排在始终运行在主线程上的主队列中之外,什么都不做。

回答by Blakedallen

Simply adding DispatchQueue.main.async will prevent this and is recommended in the swift documentation.

简单地添加 DispatchQueue.main.async 将阻止这种情况,并且在 swift 文档中推荐。

DispatchQueue.main.async { 
    //code that caused error goes here
}

回答by Puneet Sharma

XCode 9 includes a Main thread checkertool that checks whether any UIKit related stuff is happening on a main thread. It is supposed to prevent the cases where touching UIKit from a background thread, is going to create problems.

XCode 9 包含一个主线程检查器工具,用于检查主线程上是否正在发生任何与 UIKit 相关的事情。它应该防止从后台线程触摸 UIKit 会产生问题的情况。

Although, it is advisable to keep this tool around, but if its too much a bother for you, you can turn it off:

虽然,建议保留此工具,但如果它对您来说太麻烦,您可以将其关闭:

XCode->Edit Scheme->Target->Diagnostics-> Uncheck RunTime API Checking

XCode->Edit Scheme->Target->Diagnostics-> Uncheck RunTime API Checking

enter image description here

在此处输入图片说明

回答by Krunal

Here is Apple Guideline on Main Thread Checker

这是主线程检查器的 Apple 指南

  • New in Xcode 9 – Main Thread Checker.
    • Enable detection of UI API misuse from background thread
    • Detects AppKit, UIKit, and WebKit method calls that are not made on the main thread.
    • Automatically enabled during debugging, and can be disabled in the Diagnostic tab of the scheme editor.
    • Main Thread Checker works with Swift and C languages.
  • Xcode 9 中的新功能——主线程检查器。
    • 启用从后台线程检测 UI API 滥用
    • 检测不是在主线程上进行的 AppKit、UIKit 和 WebKit 方法调用。
    • 在调试期间自动启用,并且可以在方案编辑器的诊断选项卡中禁用。
    • 主线程检查器适用于 Swift 和 C 语言。

Try this: Replace your code with following one, and see. It's a permanent solution, without disabling warning.

试试这个:用下面的代码替换你的代码,然后看看。这是一个永久的解决方案,没有禁用警告。

@IBAction fund saveButtonTapped(_ sender: Any) {


    LoginManager.checkLoginStatus { isLogged in

        if isLogged {

            // Updates your UIs on main queue
            DispatchQueue.main.async(execute: {

            if self.priceTextField.text == "" {
                GlobalVariables.sharedManager.itemPrice = 0
            } else {
                GlobalVariables.sharedManager.itemPrice = Double(self.priceTextField.text!)!
            }

            if self.titleTextView.text == "" {
                GlobalVariables.sharedManager.expenseTitle = "N/A"
            } else {
                GlobalVariables.sharedManager.expenseTitle = self.titleTextView.text!
            }

            if self.descriptionTextView.text == "" {
                GlobalVariables.sharedManager.expenseDescription = "N/A"
            } else {
                GlobalVariables.sharedManager.expenseDescription = self.descriptionTextView.text!
            }

            if self.categoryPickerTextFld.text == "" {
                GlobalVariables.sharedManager.expenseCategory = "N/A"
            } else {
                GlobalVariables.sharedManager.expenseCategory = self.categoryPickerTextFld.text!
            }


            if self.imageView.image == nil {
                GlobalVariables.sharedManager.expenseSelectedImage = nil
            } else {
                GlobalVariables.sharedManager.expenseSelectedImage = self.imageView.image
            }


            }) 

        }
    }
}



or, you can just disable warning, by disabling main thread checker from your project target



或者,您可以通过禁用项目目标中的主线程检查器来禁用警告

(Xcode Project Target - Below Device List) >> Edit Scheme >> Target >> Diagnostics >> RunTime API Checking - Uncheck

(Xcode 项目目标 - 在设备列表下方)>> 编辑方案 >> 目标 >> 诊断 >> 运行时 API 检查 - 取消选中

enter image description here

在此处输入图片说明

回答by Anton Malmygin

The problem exactly that it is - you are using UI elements from background thread. Try to modify your code in order to access them from main thread.

问题正是如此 - 您正在使用来自后台线程的 UI 元素。尝试修改您的代码以便从主线程访问它们。

Xcode 9 have new feature - it can check problems like this on runtime and report it during execution.

Xcode 9 有一个新功能——它可以在运行时检查这样的问题并在执行期间报告它。

If you REALLY do not want it, you can disable it in scheme settings. Edit Scheme... -> (Select your scheme) -> Diagnostics -> Disable 'Main thread checker'

如果你真的不想要它,你可以在方案设置中禁用它。编辑方案...->(选择您的方案)-> 诊断-> 禁用“主线程检查器”

回答by Blake

The warnings seem overly aggressive as you imply by stating that you are only checking if a textField is empty, not changing anything on the UI. The warning is trying to discourage any use of UI elements off of the main thread, which is not a bad thing of course, but it doesn't take into account edge cases like yours.

警告似乎过于激进,因为您暗示您只是检查 textField 是否为空,而不是更改 UI 上的任何内容。该警告试图阻止在主线程之外使用任何 UI 元素,这当然不是一件坏事,但它没有考虑到像您这样的边缘情况。