UITextView 在循环期间不更新

UITextView does not update during loop

所以我尝试了两种不同的方式来在屏幕上显示计时器倒计时。

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

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


//
//  ViewController.swift
//  EggTimer
//
//  Created by Angela Yu on 08/07/2019.
//  Copyright © 2019 The App Brewery. All rights reserved.
//

import UIKit

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

class ViewController: UIViewController {
    
    @IBOutlet weak var timerTextView: UITextView!
    
    @IBAction func eggHardnessButton(_ sender: UIButton) {
        let hardness = sender.currentTitle
        func timeCountDownSoft() {
            var time = 3
            repeat {
                time = time - 1 //repeats
                timerTextView.selectAll("") // does not repeat
                timerTextView.insertText("") // does not repeat
                let timeWord = String(time) // repeats
                timerTextView.insertText(timeWord)//does not repeat
                print(time) //repeats
                sleep(1) //repeats
                
            } while time >= 1
            
            /*for timer in stride(from: 2, to: 0 , by: -1){
             let time = String(timer)
             timerTextView.selectAll("")
             timerTextView.insertText("")
             timerTextView.insertText(time)
             print(time)
             sleep(1)
             }*/
        }
        func timeCountDownMed() {
            for timer in stride(from: 420, to: 0 , by: -1) {
                print(timer)
                sleep(1)
            }
        }
        func timeCountDownHard() {
            for timer in stride(from: 720, to: 0 , by: -1) {
                print(timer)
                sleep(1)
            }
        }
        if hardness == "Soft" {
            print(softTime) // does not repeat
            timeCountDownSoft() // does not repeat
            
            
        } else if hardness == "Medium" {
            print(medTime)
            timeCountDownMed()
        } else {
            print(hardTime)
            timeCountDownHard()
        }
    }
}

您从不(好吧,几乎从不)想要使用sleep().

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

您想要做的是使用具有 one-second 间隔的重复 Timer。每次计时器触发时,减少您的计数器并更新 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()
            }
        }

    }
    
}

几点:

  • 当您的应用更改 UI 时,这些更改实际上并没有得到 呈现在屏幕上,直到您的代码 returns 并访问应用程序的 事件循环。因此,在你的重复循环中,什么都不会出现在 UI 直到循环完成

  • 不要在主线程上使用 sleep()。这阻止了一切,并且 您的应用突然停止。

  • 如果你想每秒更新一次UI,设置一个重复定时器 每秒触发一次并在计时器代码中进行 UI 更新。