iOS Timer.publish 有 14 个奇怪的行为
iOS 14 weird behavior with Timer.publish
我已尽最大努力只提取了显示这种奇怪行为的较大项目的一小部分。目的是将一个随机数添加到数组中并每 3 秒显示一次。在 iOS 13 中,每个数字每 3 秒从左侧滑入一次,一切都按预期进行。我在 iOS 14 中看到的是每 3 秒添加 4 个数字。有谁知道为什么会这样?提前致谢!
import SwiftUI
struct ContentView: View {
@State private var calledNumbers = CalledNumbers()
@State private var timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var inProgress = false
var body: some View {
Button(action: {
if !self.inProgress {
self.calledNumbers.startOver()
print("Start timer")
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
else {
print("Stop timer")
self.timer.upstream.connect().cancel()
}
self.inProgress.toggle()
})
{
if(self.inProgress == false) {
Text("S T A R T")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.background(Capsule()
.fill(Color.green))
.cornerRadius(35)
.foregroundColor(.white)
.padding(.bottom, 2)
}
else {
Text("S T O P")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(35)
.onReceive(self.timer) { _ in
self.timer.upstream.connect().cancel()
print("CALL NEXT NUMBER")
self.calledNumbers.callNextNumber()
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
}
}
ZStack {
RoundedRectangle(cornerRadius: 35)
.frame(width: UIScreen.main.bounds.size.width - 19, height: 40, alignment: .center)
.foregroundColor(.clear)
.padding(.bottom, 2)
HStack {
ForEach(self.calledNumbers.calledNumberList.reversed().filter {self.checkCount(number: [=12=])}, id: \.self) { number in
Text("\(String(number))")
.font(.custom("Menlo", size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.transition(AnyTransition.offset(x: (number == self.calledNumbers.calledNumberList.last) ? -250 : 250))
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
}
func checkCount(number: Int) -> Bool {
let count = self.calledNumbers.calledNumberList.count
if (count <= 8) {
return true
}
else {
guard let index = self.calledNumbers.calledNumberList.firstIndex(of: number) else { return false }
if (count - index > 8) { return false }
else { return true }
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
此文件由xcode 12 添加(我将此项目命名为 Test2):
import SwiftUI
@main
struct Test2App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Class 被叫号码
//
// class.swift
// Test2
//
import Foundation
class CalledNumbers {
@Published var calledNumberList: [Int]
init() {
calledNumberList = [Int]()
}
func callNextNumber() {
var tempNumber = Int.random(in: 1...75)
while calledNumberList.contains(tempNumber) {
tempNumber = Int.random(in: 1...75)
}
calledNumberList.append(tempNumber)
print("Number added \(tempNumber)")
}
func startOver() {
calledNumberList.removeAll()
}
}
问题似乎是由 .onReceived()
附加到 Button
内的代码引起的。将 .onReceived()
移动到 Button
作为一个整体解决了这个问题。
此外,您对计时器的操作超出了必要。我从 .onReceive()
.
中删除了停止和重新启动计时器
calledNumbers
应该是 @ObservableObject
.
struct ContentView: View {
@ObservedObject var calledNumbers = CalledNumbers()
@State private var timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var inProgress = false
var body: some View {
Button(action: {
if !self.inProgress {
self.calledNumbers.startOver()
print("Start timer")
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
else {
print("Stop timer")
self.timer.upstream.connect().cancel()
}
self.inProgress.toggle()
})
{
Text(inProgress ? "STOP" : "START")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.cornerRadius(35)
.foregroundColor(.white)
.background(Capsule().fill(inProgress ? Color.red : .green))
.padding(.bottom, 2)
}
}
.onReceive(self.timer) { _ in
print("CALL NEXT NUMBER")
self.calledNumbers.callNextNumber()
}
.onAppear {
// Cancel the initial timer
self.timer.upstream.connect().cancel()
}
ZStack {
RoundedRectangle(cornerRadius: 35)
.frame(width: UIScreen.main.bounds.size.width - 19, height: 40, alignment: .center)
.foregroundColor(.clear)
.padding(.bottom, 2)
HStack {
ForEach(self.calledNumbers.calledNumberList.reversed().filter {self.checkCount(number: [=10=])}, id: \.self) { number in
Text("\(String(number))")
.font(.custom("Menlo", size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.transition(AnyTransition.offset(x: (number == self.calledNumbers.calledNumberList.last) ? -250 : 250))
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
}
func checkCount(number: Int) -> Bool {
let count = self.calledNumbers.calledNumberList.count
if (count <= 8) {
return true
}
else {
guard let index = self.calledNumbers.calledNumberList.firstIndex(of: number) else { return false }
if (count - index > 8) { return false }
else { return true }
}
}
}
此外,您的 CalledNumbers
class 应该是 ObservableObject
以便 Published
正常工作:
import Foundation
class CalledNumbers: ObservableObject {
@Published var calledNumberList: [Int]
init() {
calledNumberList = [Int]()
}
func callNextNumber() {
var tempNumber = Int.random(in: 1...75)
while calledNumberList.contains(tempNumber) {
tempNumber = Int.random(in: 1...75)
}
calledNumberList.append(tempNumber)
print("Number added \(tempNumber)")
}
func startOver() {
calledNumberList.removeAll()
}
}
我已尽最大努力只提取了显示这种奇怪行为的较大项目的一小部分。目的是将一个随机数添加到数组中并每 3 秒显示一次。在 iOS 13 中,每个数字每 3 秒从左侧滑入一次,一切都按预期进行。我在 iOS 14 中看到的是每 3 秒添加 4 个数字。有谁知道为什么会这样?提前致谢!
import SwiftUI
struct ContentView: View {
@State private var calledNumbers = CalledNumbers()
@State private var timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var inProgress = false
var body: some View {
Button(action: {
if !self.inProgress {
self.calledNumbers.startOver()
print("Start timer")
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
else {
print("Stop timer")
self.timer.upstream.connect().cancel()
}
self.inProgress.toggle()
})
{
if(self.inProgress == false) {
Text("S T A R T")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.background(Capsule()
.fill(Color.green))
.cornerRadius(35)
.foregroundColor(.white)
.padding(.bottom, 2)
}
else {
Text("S T O P")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(35)
.onReceive(self.timer) { _ in
self.timer.upstream.connect().cancel()
print("CALL NEXT NUMBER")
self.calledNumbers.callNextNumber()
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
}
}
ZStack {
RoundedRectangle(cornerRadius: 35)
.frame(width: UIScreen.main.bounds.size.width - 19, height: 40, alignment: .center)
.foregroundColor(.clear)
.padding(.bottom, 2)
HStack {
ForEach(self.calledNumbers.calledNumberList.reversed().filter {self.checkCount(number: [=12=])}, id: \.self) { number in
Text("\(String(number))")
.font(.custom("Menlo", size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.transition(AnyTransition.offset(x: (number == self.calledNumbers.calledNumberList.last) ? -250 : 250))
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
}
func checkCount(number: Int) -> Bool {
let count = self.calledNumbers.calledNumberList.count
if (count <= 8) {
return true
}
else {
guard let index = self.calledNumbers.calledNumberList.firstIndex(of: number) else { return false }
if (count - index > 8) { return false }
else { return true }
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
此文件由xcode 12 添加(我将此项目命名为 Test2):
import SwiftUI
@main
struct Test2App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Class 被叫号码
//
// class.swift
// Test2
//
import Foundation
class CalledNumbers {
@Published var calledNumberList: [Int]
init() {
calledNumberList = [Int]()
}
func callNextNumber() {
var tempNumber = Int.random(in: 1...75)
while calledNumberList.contains(tempNumber) {
tempNumber = Int.random(in: 1...75)
}
calledNumberList.append(tempNumber)
print("Number added \(tempNumber)")
}
func startOver() {
calledNumberList.removeAll()
}
}
问题似乎是由 .onReceived()
附加到 Button
内的代码引起的。将 .onReceived()
移动到 Button
作为一个整体解决了这个问题。
此外,您对计时器的操作超出了必要。我从 .onReceive()
.
calledNumbers
应该是 @ObservableObject
.
struct ContentView: View {
@ObservedObject var calledNumbers = CalledNumbers()
@State private var timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var inProgress = false
var body: some View {
Button(action: {
if !self.inProgress {
self.calledNumbers.startOver()
print("Start timer")
self.timer = Timer.publish(every: 3, tolerance: 0.5, on: .main, in: .common).autoconnect()
}
else {
print("Stop timer")
self.timer.upstream.connect().cancel()
}
self.inProgress.toggle()
})
{
Text(inProgress ? "STOP" : "START")
.font(.system(size: 22))
.fontWeight(.heavy)
.frame(width: 200, height: 35, alignment: .center)
.cornerRadius(35)
.foregroundColor(.white)
.background(Capsule().fill(inProgress ? Color.red : .green))
.padding(.bottom, 2)
}
}
.onReceive(self.timer) { _ in
print("CALL NEXT NUMBER")
self.calledNumbers.callNextNumber()
}
.onAppear {
// Cancel the initial timer
self.timer.upstream.connect().cancel()
}
ZStack {
RoundedRectangle(cornerRadius: 35)
.frame(width: UIScreen.main.bounds.size.width - 19, height: 40, alignment: .center)
.foregroundColor(.clear)
.padding(.bottom, 2)
HStack {
ForEach(self.calledNumbers.calledNumberList.reversed().filter {self.checkCount(number: [=10=])}, id: \.self) { number in
Text("\(String(number))")
.font(.custom("Menlo", size: 20))
.fontWeight(.black)
.frame(width: 40, height: 40, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.transition(AnyTransition.offset(x: (number == self.calledNumbers.calledNumberList.last) ? -250 : 250))
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
}
func checkCount(number: Int) -> Bool {
let count = self.calledNumbers.calledNumberList.count
if (count <= 8) {
return true
}
else {
guard let index = self.calledNumbers.calledNumberList.firstIndex(of: number) else { return false }
if (count - index > 8) { return false }
else { return true }
}
}
}
此外,您的 CalledNumbers
class 应该是 ObservableObject
以便 Published
正常工作:
import Foundation
class CalledNumbers: ObservableObject {
@Published var calledNumberList: [Int]
init() {
calledNumberList = [Int]()
}
func callNextNumber() {
var tempNumber = Int.random(in: 1...75)
while calledNumberList.contains(tempNumber) {
tempNumber = Int.random(in: 1...75)
}
calledNumberList.append(tempNumber)
print("Number added \(tempNumber)")
}
func startOver() {
calledNumberList.removeAll()
}
}