Ios UITextView在循环期间不更新

Ios UITextView在循环期间不更新,ios,swift,loops,uitextview,Ios,Swift,Loops,Uitextview,因此,我尝试了两种不同的方式在屏幕上显示计时器倒计时 代码将打印到控制台,但不会打印到UITextView(在两种循环情况下)。在重复中,UITextView以0结尾,这是它显示的唯一内容,而不是原始txt“时间计数”。。。。在实现注释循环的情况下,UITextView仅显示1(倒计时结束)。。。尽管这些命令与UITextView位于同一个括号中,但为什么要打印到控制台上,并且它们会重复 运行代码并单击“软”后显示图像(这是应用程序brewery egg timer的衍生产品) 您从未(嗯,几

因此,我尝试了两种不同的方式在屏幕上显示计时器倒计时

代码将打印到控制台,但不会打印到UITextView(在两种循环情况下)。在重复中,UITextView以0结尾,这是它显示的唯一内容,而不是原始txt“时间计数”。。。。在实现注释循环的情况下,UITextView仅显示1(倒计时结束)。。。尽管这些命令与UITextView位于同一个括号中,但为什么要打印到控制台上,并且它们会重复

运行代码并单击“软”后显示图像(这是应用程序brewery egg timer的衍生产品)


您从未(嗯,几乎从未)想要使用
sleep()

文本未更新的原因是,您正在运行从不允许UIKit更新视图的闭环

相反,您要做的是使用间隔为
1秒的重复
计时器。每次定时器启动时,减小计数器并更新UI。当计数器达到零时,停止计时器

下面是一个简单的例子:

import UIKit

let softTime = 5
let medTime = 7
let hardTime = 12

class ViewController: UIViewController {
    
    @IBOutlet weak var timerTextView: UITextView!
    
    var theTimer: Timer?
    
    @IBAction func eggHardnessButton(_ sender: UIButton) {
        
        let hardness = sender.currentTitle
        var numSeconds = 0

        // set number of seconds based on button title
        switch hardness {
        case "Soft":
            numSeconds = softTime * 60
        case "Medium":
            numSeconds = medTime * 60
        case "Hard":
            numSeconds = hardTime * 60
        default:
            // some other button called this func, so just return
            return()
        }

        // stop current timer if it's running
        if let t = theTimer {
            if t.isValid {
                t.invalidate()
            }
        }
        
        // update text field with selected time
        let timeWord = String(numSeconds)
        self.timerTextView.text = timeWord

        // start a timer with 1-second interval
        theTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            numSeconds -= 1
            let timeWord = String(numSeconds)
            self.timerTextView.text = timeWord
            // if we've reached Zero seconds remaining
            if numSeconds == 0 {
                // stop the timer
                timer.invalidate()
            }
        }

    }
    
}
有几点:

  • 当你的应用程序改变用户界面时,这些改变实际上并没有得到响应 渲染到屏幕,直到代码返回并访问应用程序的 事件循环。因此,在重复循环中,将不会显示任何内容 直到循环完成,用户界面才会停止

  • 不要在主线程上使用sleep()。这会阻碍一切,而且 你的应用程序突然停止

  • 如果要每秒更新一次UI,请设置一个重复计时器 每秒触发一次,并在计时器代码中更新UI


sleep
停止当前线程。它将无法按照您编写的方式更新UI。如果你想使用计时器,你可以直接使用。我建议你不要使用睡眠。。。这门课真的做到了吗?我在前一段时间拍的,但是忘记了定时器在主线程上执行它的块?只是想知道UI更新。@Flander-来自苹果的文档:
创建一个计时器,并以默认模式在当前运行循环中安排它。
。。。因此,在本例中,如果在主线程上调用
eggHardnessButton()
func(例如响应
.touchupinder
),则计时器在主线程上运行。我读到@DonMag,但不确定默认模式下的
运行循环是否意味着在主线程上运行。谢谢你的澄清。
import UIKit

let softTime = 5
let medTime = 7
let hardTime = 12

class ViewController: UIViewController {
    
    @IBOutlet weak var timerTextView: UITextView!
    
    var theTimer: Timer?
    
    @IBAction func eggHardnessButton(_ sender: UIButton) {
        
        let hardness = sender.currentTitle
        var numSeconds = 0

        // set number of seconds based on button title
        switch hardness {
        case "Soft":
            numSeconds = softTime * 60
        case "Medium":
            numSeconds = medTime * 60
        case "Hard":
            numSeconds = hardTime * 60
        default:
            // some other button called this func, so just return
            return()
        }

        // stop current timer if it's running
        if let t = theTimer {
            if t.isValid {
                t.invalidate()
            }
        }
        
        // update text field with selected time
        let timeWord = String(numSeconds)
        self.timerTextView.text = timeWord

        // start a timer with 1-second interval
        theTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            numSeconds -= 1
            let timeWord = String(numSeconds)
            self.timerTextView.text = timeWord
            // if we've reached Zero seconds remaining
            if numSeconds == 0 {
                // stop the timer
                timer.invalidate()
            }
        }

    }
    
}