首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SwiftUI -计时器不会在0处停止

基础概念

SwiftUI 是苹果公司推出的一个用于构建用户界面的框架,它使用声明式编程的方式来描述用户界面。计时器(Timer)是 iOS 开发中常用的一种工具,用于在指定的时间间隔内执行某些操作。

问题描述

在 SwiftUI 中使用计时器时,可能会遇到计时器不会在 0 处停止的问题。这通常是因为计时器的逻辑没有正确处理,导致计时器无法正确停止。

原因分析

  1. 计时器逻辑错误:计时器的停止条件可能没有正确设置,导致计时器无法在 0 处停止。
  2. 状态管理问题:SwiftUI 的状态管理可能没有正确处理,导致计时器的状态无法正确更新。

解决方案

以下是一个示例代码,展示如何在 SwiftUI 中正确使用计时器并在 0 处停止:

代码语言:txt
复制
import SwiftUI
import Combine

struct ContentView: View {
    @State private var timerValue = 10
    private var cancellable: AnyCancellable?

    var body: some View {
        VStack {
            Text("Timer: \(timerValue)")
                .font(.largeTitle)
                .padding()

            Button(action: {
                startTimer()
            }) {
                Text("Start Timer")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
        .onAppear {
            startTimer()
        }
        .onDisappear {
            stopTimer()
        }
    }

    private func startTimer() {
        cancellable = Timer.publish(every: 1, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                guard let self = self else { return }
                if self.timerValue > 0 {
                    self.timerValue -= 1
                } else {
                    self.stopTimer()
                }
            }
    }

    private func stopTimer() {
        cancellable?.cancel()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

代码解释

  1. 状态管理:使用 @State 属性包装器来管理计时器的值。
  2. 计时器启动:在 startTimer 方法中,使用 Timer.publish 创建一个每秒触发一次的计时器,并通过 autoconnect 方法启动它。
  3. 计时器停止:在 stopTimer 方法中,取消计时器的订阅。
  4. 生命周期管理:在 onAppearonDisappear 方法中分别启动和停止计时器,确保计时器在视图出现和消失时正确管理。

应用场景

这个解决方案适用于需要在 SwiftUI 中使用计时器的各种应用场景,例如倒计时、定时任务等。

参考链接

通过以上解决方案,可以确保计时器在 SwiftUI 中正确运行并在 0 处停止。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Swift 中的函数式核心与命令式外壳:单向数据流

如果你不熟悉单向数据流的概念,我强烈建议你阅读我关于“在 SwiftUI 中类似 Redux 的状态容器”的系列文章。...我们将创建一个可以运行的 SwiftUI 应用示例,该应用将展示如何使用函数式核心与命令式外壳的理念来实现单向数据流和管理副作用。...这个示例将实现一个简单的计时器应用,允许用户启动、停止、重置计时器并分享计时状态。函数式核心部分首先,我们定义应用的状态和动作,并实现一个 reducer 函数来管理状态变化。...界面最后,我们创建一个 SwiftUI 界面来展示计时器功能,并连接到 Store。...SwiftUI 界面:RootView 使用 Store 提供的状态和动作来构建界面。用户可以启动、停止、重置计时器,并共享计时状态。

11300

掌握 SwiftUI 的 task 修饰器

详情请参阅 SwiftUI 视图的生命周期研究[3] 一文中有关 onAppear 和 onDisappear 的章节SwiftUI 为了判断视图的状态是否发生了改变,它会在视图的存续期内,反复地生成视图类型实例以达成此目的...task_longrun1_2022-08-07_09.07.44.2022-08-07 09_09_38我们的本意是通过按钮来开启和关闭计时器的显示以控制任务的生命周期( 关闭时结束任务 ),但在点击...是无法直接停止掉我们通过 task 修饰器创建的异步任务的。...当满足了需要停止由 task 修饰器创建的异步任务条件时,SwiftUI 会给该任务发送任务取消信号,任务必须自行响应该信号并停止作业。...例如,将上面的计时器代码修改为:struct TimerView: View { @State var date = Date.now @State var show = true var

2.2K30
  • 掌握 SwiftUI 的 task 修饰器

    详情请参阅 SwiftUI 视图的生命周期研究 一文中有关 onAppear 和 onDisappear 的章节 SwiftUI 为了判断视图的状态是否发生了改变,它会在视图的存续期内,反复地生成视图类型实例以达成此目的...图片 我们的本意是通过按钮来开启和关闭计时器的显示以控制任务的生命周期( 关闭时结束任务 ),但在点击 Hide Timer 按钮后,app 出现了无法响应且控制台仍在持续输出( 不按照原定的间隔时间...是无法直接停止掉我们通过 task 修饰器创建的异步任务的。...当满足了需要停止由 task 修饰器创建的异步任务条件时,SwiftUI 会给该任务发送任务取消信号,任务必须自行响应该信号并停止作业。...例如,将上面的计时器代码修改为: struct TimerView: View { @State var date = Date.now @State var show = true

    3.6K60

    Web前端学习 第3章 JavaScript基础教程17 计时器

    ,我们可以使用clearTimeout方法让计时器停下来,下面我们来定义一个按钮,当页面加载后,如果我们在3秒钟之内点击按钮,计时器停止,不会输出hello world,如果不点击按钮,3秒钟之后就会输出...4 },3000) 5 btn.onclick = function(){ 6 clearTimeout(t); 7 } setTimeout方法会返回一个整数类型的值,通过这个值,我们可以停止计时器...,我们将setTimeout方法的返回值赋值给一个变量,当点击按钮的时候,使用clearTimeout方法,传入t,这样计时器就会停止,hello world就不会在控制台输出。...这个案例会一直输出数字,下面我们来改进这个例子,当数字为10的时候就停止,效果看起来有些想之前讲过的for循环输出数字,但用计时器输出可以实现每个1秒输出一个数字,而不是连续的输出 1 var n...我们还可以继续用按钮控制计时器,这次我们定义一个h1标签存放数字,再用两个按钮来实现“开始计数”和“停止计数”功能 1 0 2 <button id="start

    1.5K20

    Airbnb 的三阶段 SwiftUI 迁移实践

    Airbnb 的工程师认为,SwiftUI 的主要优势是它的灵活性和可组合性、声明性、简洁性和惯用性,他们希望这些优势可以改进开发者体验,同时不会在用户体验方面有所损失。...简单地说,桥接是基于 UIHostingViewController(将 SwiftUI 层次结构嵌入到视图控制器)和 UIViewRepresentable(将 UIKit 视图集成到 SwiftUI...Airbnb 工程师做出的另一个决定是将 Epoxy 的单向数据流应用到 SwiftUI,将 ObservableOject 作为状态类的基础,在每次状态变化时触发 SwiftUI 重新渲染。...他们的新 SwiftUI 实现需要能够很好地适应他们的快照测试方法。...关于 Airbnb 采用 SwiftUI,这里无法全部概述,所以请不要错过原文的内容和一些有用的代码片段。

    21810

    如何在Xcode下预览含有Core Data元素的SwiftUI视图

    如何在Xcode下预览含有Core Data元素的SwiftUI视图 从SwiftUI诞生之日起,预览(Canvas Preview )一直是个让开发者又爱又恨的功能。...预览模拟器不支持控制台输出显示、不支持断点调试,即使在动态预览模式下(支持交互的预览模式),我们也不会在Xcode中获得任何代码中的控制台输出内容。因此在预览发生问题时,用于排查故障的手段很有限。...有时需要重启Xcode甚至重启系统才会恢复正常 SwiftUI下的Core Data SwiftUI App life cycle 从Xcode 12开始,开发者可以在Xcode中使用SwiftUI原生的应用程序生命周期创建项目...Redux-like SwiftUI + Combine是苹果推出的声明+响应式结构方案。SwiftUI应用程序的开发逻辑非常类似于Redux设计模式。...在这种模式下,通常我们不会在视图中执行复杂的行为(同视图描述无关),通过向Store发送Action让Reducer完成程序的State调整,视图仅仅是对当前状态的一种呈现。

    5.1K10

    避免 SwiftUI 视图的重复计算

    随着近年来有关 SwiftUI 的文章与书籍越来越多,开发者应该都已经清楚地掌握了 —— “视图是状态的函数” 这一 SwiftUI 的基本概念。...符合 DynamicProperty 协议的属性包装器 几乎每一个 SwiftUI 的使用者,在学习 SwiftUI 的第一天就会接触到例如 @State、@Binding 这些会引发视图更新的属性包装器...当 SwiftUI 将视图从视图树上删除时,会一并完成对 SwiftUI 数据池以及关联的清理工作。如此,使用 State 包装的变量,其存续期将与视图的存续期保持完全一致。...并且 SwiftUI 会在其变化时自动更新( 重新计算 )对应的视图。 SwiftUI 上有一个困扰了不少人的问题:为什么无法在视图的构造函数中,更改 State 包装的变量值?...fieldOffset: Int, inputs: inout _GraphInputs) } @ObservedObject 与 @StateObject 最大的区别是,ObservedObject 并不会在

    9.3K81

    如何判断 ScrollView、List 是否正在滚动中

    遗憾的是,SwiftUI 并没有提供这方面的 API 。本文将介绍几种在 SwiftUI 中获取当前滚动状态的方法,每种方法都有各自的优势和局限性。...)开始滚动时调用此方法scrollViewDidEndDecelerating(_ scrollView: UIScrollView)手指滑动可滚动区域后( 此时手指已经离开 ),滚动逐渐减速,在滚动停止时会调用此方法...目前 SwiftUI 在内部的实现上去 UIKit( AppKit )化很明显,比如,本节介绍的方法在 SwiftUI 4.0 中已经失效方法二:Runloop我第一次接触 Runloop 是在学习 Combine...in self.timestamp = Date() // 如果 0.15 秒后没有继续收到位置变化的信号,则发送滚动状态停止的信号...判断的准确度没有前两种方式高当可滚动组件中的内容出现了非滚动引起的尺寸或位置的变化( 例如 List 中某个视图的尺寸发生了动态变化 ),本方式会误判断为发生了滚动,但在视图的变化结束后,状态会马上恢复到滚动结束滚动开始后( 状态已变化为滚动中 ),保持手指处于按压状态并停止滑动

    3.8K40

    前端节流(throttle)和防抖动(debounce)

    但事实上在这类场景里,有价值的请求只会发生在用户停止输入后,通俗来说就是用户输入过程中的字符串不必当真。 Debounce 就是用来过滤输入过程中无意义的响应。...实现上,只需要设置一个定时器(setTimeout),并在定计时器启动后(如 3 秒后)执行这个回调函数;若在定时器启动前又有相同回调到来,便取消之前的定时器(clearTimeout)——之前的回调便取消了...若 immediate 被设成了 true 并且没有开启的计时器(!timeout),则能被callNow,便会立即执行 cb(不会在 setTimeout 里执行)。...防抖是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,都会清除当前的 timer 然后重新设置超时调用,即重新计时。这样一来,只有最后一次操作能被触发。...节流是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器

    3.5K20

    GeometryReader :好东西还是坏东西?

    本章节包含了许多关于 SwiftUI 的尺寸和布局的知识。...如果你对此还不太了解,建议你继续阅读以下文章:SwiftUI 布局 —— 尺寸(上)[5]、SwiftUI 布局 —— 尺寸(下)[6]、SwiftUI 布局 —— 对齐[7]。...为此,我们首先需要理解 SwiftUI 的布局原理。 SwiftUI 的布局是一个协商过程。父视图向子视图提供建议尺寸,子视图返回需求尺寸。...这既保证了信息获取的准确性(尺寸、位置与要获取的视图完全一致),也不会在视觉上造成额外的影响。...请阅读 用 SwiftUI 的方式进行布局[9] 和 在 SwiftUI 中实现视图居中的若干种方法[10] 两篇文章,以了解面对同一个需求,SwiftUI 有多种布局手段。

    61070

    一段因 @State 注入机制所产生的“灵异代码”

    State 注入的优化机制在 SwiftUI 中,对于引用类型,开发者可以通过 @StateObject、@ObservedObject 或 @EnvironmentObject 将其注入到视图中。...与之不同的是,针对值类型的主要注入手段 @State,SwiftUI 则为其实现了高度的优化机制( EnvironmentValue 没有提供优化,行为与引用类型注入行为一致 )。...is", n) // 无论是否注释掉上面的 Text ,此处均打印为 2 } }}尽管我们通过 .fullScreenCover 在 Text 中引用了 n , 但由于该段代码并不会在...在 SwiftUI 早期的版本中,对于分别位于不同上下文的独立的视图树,开发者需要显式为 Sheet 视图树注入环境依赖。后期版本已为开发者自动完成该注入工作。...而 SwiftUI 为了优化效率,通常会对若干操作进行合并。

    1.9K20

    AVKit框架详细解析(四) —— 基于AVKit 和 AVFoundation框架的视频流App的构建

    播放器对象可以启动和停止您的视频,更改其播放速率,甚至可以调高和调低音量。 将播放器视为能够一次管理一个媒体资产的播放的控制器对象。...问题是你不能直接在 SwiftUI 中使用这个层。 毕竟 SwiftUI 没有 CALayer的概念。 为此,您需要回到 UIKit。...通过将速率设置为 0.0 来停止视频剪辑播放: embeddedVideoRate = 0.0 要在全屏视频关闭时恢复播放,请在 VideoFeedView 主体中找到 fullScreenCover...视图修饰符,并在 On Dismiss Closure 注释后添加以下内容: embeddedVideoRate = 1.0 当系统不再需要播放器对象时,您还可以停止播放视频并从播放器对象中删除所有项目...当您返回到feed时,预览会从停止的地方恢复。 6. Trying Not to Steal the Show 如果您打算制作一个包含视频的应用,那么考虑您的应用将如何影响您的用户非常重要。

    7K10
    领券