swift NSTimer干扰用户点击

qeeaahzv  于 2023-01-12  发布在  Swift
关注(0)|答案(1)|浏览(103)

我正在尝试非常频繁地更新一个SwiftUI X1 M0 N1 X。那个图像视图是可以点击的,如果选择它,它会得到一个高亮显示。
当使用NSTimer以较短的间隔(0.25秒)更新图像时,我的SwiftUI视图不再正确响应用户点击-只是间歇性地捕捉点击。如果我将计时器间隔设置为1秒,事情会正常工作,但在我的特定情况下,这是不可能的。
如何确保我的SwiftUI ImageonTapGesture即使在高计时器频率下也能顺利工作?
计时器声明如下:

let timer = Timer(timeInterval: 0.5, repeats: true, block: { [weak self] timer in
            guard let strongSelf = self else {
                timer.invalidate()
                return
            }

            // updating an observable object here which will be propagated to the ScreenElement view below
        })
        timer.tolerance = 0.2

        RunLoop.current.add(timer, forMode: .common)

然后我将SwiftUI视图声明为:

struct ScreenElement: View {
    var body: some View {
        VStack(alignment: .center, spacing: 12)
        {
            Image(nsImage: screen.imageData)
                .resizable()
                .aspectRatio(174/105, contentMode: .fit)
                .background(Asset.gray900.swiftUIColor)
                .cornerRadius(12)

            Text(screen.name)
        }
        .padding(EdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8))
        .onTapGesture {
            // modify data source and mark this current element as the highlighted (selected) one
        }
    }
}

我尝试过的:

我试着将计时器移到后台线程,但这并没有真正起作用,而且/或者导致的问题比它解决的更多。此外,我试着增加计时器间隔,但这在我的用例中是不可行的,因为它必须是一个非常高的刷新率。

我还有一些考虑,但无法回答:

有没有可能SwiftUI不支持每秒4次的频繁刷新?或者我在特殊情况下使用了错误的UI元素来处理点击手势?或者因为主线程过载,所以不可能有这样频繁更新的计时器?
任何帮助将不胜感激!

e4eetjau

e4eetjau1#

以下程序在iPhone和Mac上运行良好,所有点击都能被识别,并且每秒更新10次:

struct ContentView: View {

    let imageNames = ["eraser", "lasso.and.sparkles", "folder.badge.minus", "externaldrive.badge.xmark", "calendar.badge.plus", "arrowshape.zigzag.forward", "newspaper.circle", "shareplay", "person.crop.square.filled.and.at.rectangle.fill"]
    
    @State private var currentImageNames: [String] = ["", "", ""]
    @State private var selected: Int?

    var body: some View {
        VStack {
            HStack {
                ForEach(0..<3, id: \.self) { index in
                        Image(systemName: currentImageNames[index])
                            .imageScale(.large)
                            .frame(width: 80, height: 60)
                            .contentShape(Rectangle())
                            .onTapGesture {
                                selected = index
                            }
                            .background(
                                Rectangle()
                                    .fill(selected == index ? .red : .blue)
                            )
                }
            }
        }
        .onAppear {
            addTimer()
        }
        .padding()
    }
    
    func addTimer() {
        let timer = Timer(timeInterval: 0.1, repeats: true) { timer in
            currentImageNames = [imageNames.randomElement()!, imageNames.randomElement()!, imageNames.randomElement()!]
        }
        RunLoop.current.add(timer, forMode: .common)
    }
}

您可能正在执行的其他操作阻塞了主队列吗?

相关问题