You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI调用mutating func更新View实现模拟时钟秒针自动刷新

SwiftUI 采用声明式渲染范式,不需要直接调用视图实例方法修改属性,所有视图更新都由数据状态变化驱动,你的问题核心是状态链路没有打通,修改方案如下:

1. 修正 ClockHand 视图定义

@State 仅适合视图内部私有状态,这里秒针角度是外部传入的渲染参数,直接用普通 let 即可,不需要自定义更新方法:

struct ClockHand: View {
    let type: ClockHandType
    let angle: Double // 去掉@State,改为外部传入的常量
    var x: CGFloat
    var y: CGFloat
    var length: CGFloat
    var size: CGFloat
    
    var body: some View {
        RoundedRectangle(cornerRadius: 5)
            .fill(type.getColor())
            .frame(width: size*type.getWidth(), height: length )
            .position(x: x, y: y)
            .offset(y: -length/2)
            .rotationEffect(Angle.degrees(angle))
    }
    // 删掉多余的mutating update方法
}

2. 完善 ViewModel 逻辑

首先修正代码里的两处错误:原 initClock 方法名拼写和 activeWorldClock 属性缺失,再把定时器逻辑移到 ViewModel 内部,每秒触发状态更新通知:

class ClockViewModel: ObservableObject {
    @Published private var model: ClockModel
    // 内部维护定时器
    private var timer: Timer?

    init(){
        model = ClockViewModel.initClock() // 修正原拼写错误initClocks -> initClock
        // 启动定时器每秒触发更新
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            // 手动发送更新通知,触发视图重新读取计算属性activeClock
            self?.objectWillChange.send()
        }
    }
    
    static func initClock()->ClockModel {
        let places = [
            "Europe/Bern",
        ]
        return ClockModel(number: places.count){ index in
            places[index]
        }
    }

    var activeClock: TransformedClock {
        TransformedClock(clock: model.activeWorldClock!)
    }
    
    struct TransformedClock:Identifiable {
        var id:Int
        var secondAngle:Double
        var clock:ClockModel.WorldClock
        
        init(clock:ClockModel.WorldClock){
            let second = clock.calendar.component(.second, from: Date())
            self.clock  = clock
            self.id     = clock.id
            self.secondAngle = Double(second)/60.0*360
        }
    }
}

同时在 ClockModel 中补上缺失的当前激活时钟属性:

struct ClockModel{
    var worldClocks: [WorldClock]
    // 补上缺失的activeWorldClock属性
    var activeWorldClock: WorldClock? {
        worldClocks.first
    }

    // 其余原有代码保持不变
    init(number: Int, timeFactory: (Int)->String){
        worldClocks = [WorldClock]()
        for index in 0..<number{
            let place = timeFactory(index)
            var calendar = Calendar.current
            
            worldClocks.append(
                WorldClock(
                    id:         index,
                    calendar:   calendar,
                    place:      place // 你原代码里的formatPlaceString如果有实现就保留
                )
            )
        }
    }
    
    struct WorldClock:Identifiable {
        let id: Int // 补上id的属性声明
        var calendar: Calendar
        var place: String
    }
}

3. 修正 ClockView 状态绑定

给 viewModel 加上 @ObservedObject 包装器,才能响应 ViewModel 的状态更新通知,同时删掉 View 内部的定时器,直接用 ViewModel 提供的最新数据渲染:

struct ClockView: View {
    @ObservedObject var viewModel: ClockViewModel // 加上@ObservedObject
    var size: CGFloat
    
    // 删掉内部的timer定义,由ViewModel维护更新
    
    var body: some View {
        let clock = viewModel.activeClock // 每次视图刷新时自动拉取最新的时钟数据
        Circle()
            .fill(.white)
            .frame(width: size, height: size)
            .overlay{
                GeometryReader{ geometry in
                    let radius = geometry.size.width/2
                    let midX = geometry.safeAreaInsets.top + radius
                    let midY = geometry.safeAreaInsets.leading + radius
                    
                    ClockFace(size: size, radius: radius, x: midX, y: midY)
                    
                    ClockHand(
                        type: .second,
                        angle: clock.secondAngle, // 传入最新的角度自动触发重绘
                        x: midX,
                        y: midY,
                        length: radius-size*0.04,
                        size: size
                    )
                }
            }
    }
}

修改完成后,每秒 ViewModel 会触发状态更新,ClockView 会自动拉取最新的秒针角度传入 ClockHand,系统会自动完成重绘,无需手动操作视图实例。

内容的提问来源于stack exchange,提问作者Remo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 11:39:00