SwiftUI + Combine = Reactive Programming

SwiftUI的declarative programming,再加上Combine的State和Data Flow Control,让我们可以用Reactive Programming来写iOS app。今天要写一个简单的小app来向你们证明这有多简单,比之前UIKit和OC写起来简单多了,谁用谁知道!

之前在上看到一面试题:用UILabel写一个循环播放的通告,就写一下这个吧。但我想多展示一些学到的知识,所以在写之前,我们要选择一个design pattern。有了SwiftUI,以前的UIViewController的需求就更少了,所以我们选择MVVM(Model-View-ViewModel)。熟悉React的开发者可能会想能不能用Redux,答案是肯定的!我下一步就会写一个更复杂的拥有完整功能的app,就用SwiftUI、Combine和Redux来实现,到时候会放到github上去。
Github Source

先来简单说一下这个app的“知识点”:

1、Timer

因为通告是循环播放的,我们需要一个timer让通告每秒更新一次,这个不需要在background进行,所以我们就用Runloop.main中的timer就行。Combine有个方便的方法创建一个timer publisher:

Timer
            .publish(every: interval, on: .main, in: .common)
            // timer publisher只有call connect()之后才会开始发送,autoconnect就是只要用subscriber就自动开始
            .autoconnect()

2、State & Data Flow

  • @State
    如果一个variable只在View内部使用,那么我们可以用@State来声明,声明之后无论何时这个variable更新,那么View也会随之更新,栗子:
  @State private var isOn = false
    
  var body: some View {
        VStack{
            Button(action: {
                self.isOn.toggle()
            }) {
                Text("点我")
            }
            if isOn {
                Text("开了")
            }
        }
    }
  • @Binding
    如果这个View中有child view,在child view中,我们也想使用isOn这个state variable,这时候我们就需要在child view中声明一个binding variable
var body: some View {
        VStack{
            Button(action: {
                self.isOn.toggle()
            }) {
                Text("点我")
            }
            if isOn {
                Text("开了")
            }
            CView(isOn: $isOn) // a
        }
    }

struct CView: View {
    @Binding var isOn: Bool
    var body: some View {
        VStack{
            Text("Child View")
            if isOn {
                Text("我也开了")
            }
        }
    }
}

a) 注意在给CView传入isOn的时候前面要加$, 因为CView中的isOn前面有@Binding,他是一个Binding, 在body里的isOn加上$也就成了Binding

b) 这不是完整的代码,每次点击Button时,因为isOn的更新,child view和parent view会一起刷新

  • @ObservableObject
    ObservableObject是一个protocol,conform to ObservableObject的class中可以用@Published来wrap属性,一旦用了@Published,每当这个属性更新时,使用这个class和这个属性的View就会刷新一下, ViewModel就是最适合conform的
class AnnouncementViewModel: ObservableObject {
    @Published private(set) var announcement : Announcement
     // 其他完整代码可以到github下载
}
  • @ObservedObject
    有了ObservableObject之后,我们就可以在View里声明@ObservedObject了。声明之后就可以在UI中显示这个object的一些属性,然后每当这个属性更新,UI也会随之变化
struct TestView: View {
    
    @ObservedObject var viewModel = AnnouncementViewModel()
    
    var body: some View {
        Text(viewModel.announcement.title)
    }
}

Github Source

你可能感兴趣的:(SwiftUI + Combine = Reactive Programming)