
SwiftUI é uma tecnologia jovem e ainda não totalmente explorada. Por um lado, existe um grande espaço de criatividade e exploração e, por outro, incertezas, instabilidades e problemas.
É tão fácil escrever em SwiftUI como mostrado na WWDC? Contarei a você as dificuldades que encontrei pessoalmente ao escrever meu próprio requerimento. Ele foi escrito inteiramente em SwiftUI e está disponível na App Store .
? .
View
, . MVI, . MVI MVI SwiftUI –
:
@ObservedObject @StateObject
MVI , , Intent. View Intent .
struct ContentView: View {
@ObservedObject var intent: ContentIntent
var body: some View {
Text("Hello, world!")
}
}
@ObservableObject , , View, , , , UI .
.
View SwiftUI — View, , init . , View , View, , .
, View .
// MARK: - Screen ContentView
struct ContentView: View {
@State var isNextScreenVisible = false
@State var seconds = "0"
var body: some View {
NavigationView {
VStack(spacing: 16) {
Text("Seconds: \(seconds)")
NavigationLink("Next screen", destination: NextView(), isActive: $isNextScreenVisible)
}
}.onAppear {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
self.seconds = String(Int(Date().timeIntervalSince1970) % 60)
}
}
}
}
// MARK: - Scren NextView
struct NextView: View {
@ObservedObject var intent: NextIntent
init() {
intent = ContentIntent()
print("init NextView")
}
var body: some View {
Text("Hello Weold!")
}
NextView, . :
init NextView init NextView init NextView init NextView init NextView init NextView init NextView init NextView init NextView
init, View , ( Intent), , . , . . .
, @ObservedObject @StateObject Intent View.
?
View , ( MVI Intent Model, MVVM ViewModel).
, Intent , @StateObject; Intent, Intent . @StateObject Singleton, .
, Intent , @StateObject, init Intent .
@StateObject iOS 14.
@ObservedObject, Singleton?
, .
struct ContentView: View {
@ObservedObject var intent: ContentInten
init() {
self.intent = ContentInten.shared
let model = ContentModel()
self.intent.update(model: model)
}
var body: some View {
Text("Hello, world!")
}
, :
Intent ( , , . .)
Singleton
, Singleton .
SwiftUI iOS 14 , , iOS 14 SwiftUI.
@StateObject init View
. Intent View. , , , .
struct ContentView: View {
@StateObject var intent: ContentInten
var body: some View {
Text("Hello, world!")
}
static func build() -> some View {
let model = ContentModel()
let intent = ContentInten(model: model)
return ContentView(intent: intent)
}
, iOS 13.
onAppear onDisappear
, View , , View . , onAppear onDisappear , . . .
struct ContentView: View {
@State var isVisibleHomeScreen = false
var body: some View {
NavigationView {
VStack {
Text("Hello, world!")
NavigationLink(destination: Text("Screen Home"),
isActive: $isVisibleHomeScreen,
label: { Text("Open screen") })
}.onAppear {
print("onAppear was called")
}.onDisappear {
print("onDisappear was called")
}
}
}
NavigationView . :
onDisappear was called onAppear was called
, NavigationView , , . onAppear onDisappear . - .
SwiftUI? , , UIKit . , SwiftUI. , , , . , , WWDC. , "some View".
, , MVI. , , , , .
Router
// ContentRouter.swift
//
// Copyright © 2020 Vyacheslav Ansimov. All rights reserved.
//
import SwiftUI
import Combine
// MARK: - Realization
struct ContentRouter: View {
enum ScreenType {
case sheetScreen(value: String)
case navigationScreen(value: String)
case exit
}
private class ScreenTypeHolder: ObservableObject {
@Published var type: ScreenType?
}
// API
let screen: PassthroughSubject<ScreenType, Never>
// private
@Environment(\.presentationMode) private var presentationMode
@StateObject private var screenType = ScreenTypeHolder()
// Life cycle
var body: some View {
displayView().onReceive(screen) { self.screenType.type = $0 }
}
private func displayView() -> some View {
let isVisible = Binding<Bool>(get: { screenType.type != nil },
set: { if !$0 { screenType.type = nil } })
// Screens
switch screenType.type {
case .sheetScreen(let value):
return AnyView(
Spacer().sheet(isPresented: isVisible) {
Text(value)
}
)
case .navigationScreen(let value):
return AnyView (
NavigationLink("", destination: Text(value), isActive: isVisible)
)
case .exit:
presentationMode.wrappedValue.dismiss()
return AnyView(EmptyView())
case .none:
return AnyView(EmptyView())
}
}
}
// MARK: - Example
struct ContentRouter_Previews: PreviewProvider {
static let routeSubject = PassthroughSubject<ContentRouter.ScreenType, Never>()
static var previews: some View {
NavigationView {
VStack {
Button(action: {
self.routeSubject.send(.sheetScreen(value: "Hello World!"))
}, label: { Text("Display Sheet Screen") })
Button(action: {
self.routeSubject.send(.navigationScreen(value: "Hello World!"))
}, label: { Text("Display NavigationLink Screen") })
}
.overlay(ContentRouter(screen: routeSubject))
}
}
}
Property wrapper (State, Binding, ObservedObject .) SwiftUI UI.
. , ObservableObject View
// MARK: Model
class ContentModel: ObservableObject {
@Publised var title = "Hello World!"
}
// MARK: View
struct ContentView: View {
@ObservedObject var model: ContentModel
var body: some View {
Text(model.title)
}
}
, ? .
Intent. , View.
// MARK: View
struct ContentView: View {
@StateObject var intent: ContentIntent
var body: some View {
Text(intent.model .title).onAppear {
self.intent.onAppear()
}
}
}
// MARK: Intent
class ContentIntent {
let model: ContentModel
...
func onAppear() {
model.title = "Hello World!"
}
}
// MARK: Model
class ContentModel: ObservableObject {
@Published var title = "Loaded"
}
, UI Text "Loaded", .
let model: ContentModel
@Published var model: ContentModel
. ObservableObject Model Intent , - , View.
, View Model - , Intent . , Intent ObservableObject.
import Combine
class ContentIntent: ObservableObject {
let model: ContentModel
private var cancellable: Set<AnyCancellable> = []
init(model: ContentModel) {
self.model = model
cancellable.insert(model.objectWillChange.sink { [weak self] in
self?.objectWillChange.send()
})
}
...
}
Model - , objectWillChange, Intent , Model . Intent objectWillChange.send(), View .
ObservableObject Intent , objectWillChange.
. UI View, .
UI
, UIKit, SwiftUI. SwiftUI . . , , .
UI :
UISearchBar SwiftUI , , .
UIPageControll. SwiftUI - TabBar, , UIPageControll.
PikerView: , . , PikerView. , , .
TextEditor: background, .
! . . , , . , Apple .
SwiftUI?
Definitivamente não. Haverá problemas com a implementação de projetos, haverá dificuldades arquitetônicas. Como a tecnologia é nova, haverá muitas pesquisas e muitos problemas para resolver. Por outro lado, a velocidade de desenvolvimento da IU no SwiftUI é várias vezes maior do que no UIKit, e amplas possibilidades para trabalhar com animações se abrem - o SwiftUI tem animações muito bonitas e é muito fácil de fazer.
Você pode traduzir parcialmente em telas simples do SwiftUI, telas da categoria Bem-vindo ou telas de informações. Aqui, o SwiftUI tem um bom desempenho, os problemas são mínimos e, visualmente, com animações parece melhor do que o UIKit.
Também recomendo experimentá-lo em seus projetos pessoais, não muito grandes e complexos, onde não haja requisitos de design rígidos.