Skip to content

Instantly share code, notes, and snippets.

@Lascorbe
Created June 24, 2020 23:10
Show Gist options
  • Save Lascorbe/0149dd60279a3e724eced614fe3827ed to your computer and use it in GitHub Desktop.
Save Lascorbe/0149dd60279a3e724eced614fe3827ed to your computer and use it in GitHub Desktop.
import SwiftUI
import PlaygroundSupport
class Presenter: ObservableObject {
@Published var viewModel: ViewModel
private var timer: Timer!
private var memoryAddress: String!
init(prefix: String) {
self.viewModel = ViewModel(number: 0, prefix: prefix)
memoryAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
print("Presenter init: \(memoryAddress!) - '\(prefix)'")
}
func onAppear() {
print("Presenter onAppear: \(memoryAddress!)")
timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
guard let self = self else { return }
print("Presenter onAppear completion: \(self.memoryAddress!)")
self.viewModel = ViewModel(number: self.viewModel.number + 1, prefix: self.viewModel.prefix)
}
}
deinit {
print("Presenter deinit: \(memoryAddress!)")
timer?.invalidate()
}
}
extension Presenter: Equatable {
static func == (lhs: Presenter, rhs: Presenter) -> Bool {
lhs.memoryAddress == rhs.memoryAddress
}
}
struct ViewModel: Equatable {
let number: Int
let prefix: String
var name: String {
"\(prefix) \(number)"
}
}
struct ParentView: View {
@State var isPresented = false
var body: some View {
VStack {
NavigationLink("Push view", destination: getNextView())
}
}
private func getNextView() -> some View {
ContentView(presenterObserved: Presenter(prefix: "ObservedObject"))
.environmentObject(Presenter(prefix: "EnvironmentObject"))
}
}
struct ContentView: View {
@StateObject var presenter = Presenter(prefix: "StateObject")
@ObservedObject var presenterObserved: Presenter
@EnvironmentObject var presenterEnvironment: Presenter
@State var text1 = "Hello 1!"
@State var text2 = "Hello 2!"
@State var text3 = "Hello 3!"
@State var isPresented = false
@StateObject private var runOnce = RunOnce()
var body: some View {
VStack {
Text(text1)
.padding()
.onChange(of: presenter.viewModel) { value in
text1 = presenter.viewModel.name
}
Text(text2)
.padding()
.onChange(of: presenterObserved.viewModel) { value in
text2 = presenterObserved.viewModel.name
}
Text(text3)
.padding()
.onChange(of: presenterEnvironment.viewModel) { value in
text3 = presenterEnvironment.viewModel.name
}
NavigationLink("Push view", destination: getNextView(from: "Navigation"))
Button("Modal view") {
isPresented.toggle()
}.sheet(isPresented: $isPresented) {
getNextView(from: "Sheet")
}
}
.onAppear {
onAppear()
}
}
private func onAppear() {
runOnce.execute {
presenter.onAppear()
presenterObserved.onAppear()
presenterEnvironment.onAppear()
}
}
private func getNextView(from: String) -> some View {
ContentView(presenterObserved: Presenter(prefix: "\(presenterObserved.viewModel.prefix): \(from)"))
.environmentObject(Presenter(prefix: "\(presenterEnvironment.viewModel.prefix): \(from)"))
}
}
let view = NavigationView { ParentView() }
PlaygroundPage.current.liveView = UIHostingController(rootView: view)
// Helpers
class RunOnce: ObservableObject {
var didRun: Bool = false
func execute(_ block: () -> Void) {
guard !didRun else { return }
block()
didRun = true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment