Home > AI > IOS > SwiftUI >

onReceive with ObservableObject

Example: refresh the view with onReceive, without onAppear (which only called once). This example needs to correctly show the preparation seconds for the user to do the specific quiz.

TemplateView.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import SwiftUI
 
struct TemplateView: View {
    @ObservedObject var model = TemplateViewModel()
     
    @State var prepareSeconds: Int = 10
    private var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
     
     
    init() {
        self._prepareSeconds = State(initialValue: model.getTime(idx: model.currentIdx))
    }
     
 
 
    var body: some View {
        NavigationView {
            VStack {
                Text(prepareSeconds.description)
                    .onReceive(timer) { (time) in
                        prepareSeconds -= 1
                    }
                    .onReceive(model.$currentIdx, perform: { (_) in
                        prepareSeconds = model.getTime(idx: model.currentIdx)
                    })
     
                 
                NavigationLink(
                    destination: InfoView(),
                    label: {
                        Text(model.getContent(idx: model.currentIdx))
                             
                    })
                 
                Image(systemName: "arrowshape.turn.up.right.fill")
                    .onTapGesture {
                        if model.currentIdx >= model.data.count-1 {
                            model.currentIdx = 0
                        } else {
                            model.currentIdx += 1
                        }
                    }
            }
        }
    }
}

TemplateViewModel.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TemplateViewModel: ObservableObject {
    @Published var currentIdx: Int = 0
     
    var data: [QuizModel] = [
        QuizModel(prepareSeconds: 10, content: "Answer the short question"),
        QuizModel(prepareSeconds: 20, content: "Listen to the audio"),
        QuizModel(prepareSeconds: 30, content: "Read the article"),
    ]
     
    func getTime(idx: Int) -> Int {
        
        return data[idx].prepareSeconds
    }
     
    func getContent(idx: Int) -> String {
        return data[idx].content
    }
     
}

InfoView.swift

1
2
3
4
5
6
7
8
9
10
struct InfoView: View {
    @Environment(\.presentationMode) var mode
 
    var body: some View {
        Text("good")
            .onTapGesture {
                mode.wrappedValue.dismiss()
            }
    }
}

Leave a Reply