New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to reload data without using onAppear in SwiftUI in watchOS #468
Comments
Curious if this is a retain cycle given
|
@micahnap It's a struct, no no weak strong |
I am using SwiftUI on Xcode 11.2 Here is the little code. protocol PREVRouteDelegate: class {
func show()
func push()
}
final class PREVHostingVC: UIHostingController<AnyView>, PREVRouteDelegate {
class ROUTE: ObservableObject {
var delegate: PREVRouteDelegate? = nil
init() {}
}
init() {
let route = ROUTE()
super.init(rootView: AnyView(PREV().environmentObject(route)))
route.delegate = self
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
print("UIKIT.DIDLOAD")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("UIKIT.WILLAPPEAR")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("UIKIT.DIDAPPEAR")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("UIKIT.WILLDISAPPEAR")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("UIKIT.DIDDISAPPEAR")
}
func show() {
let vc = NEXTHostingVC()
vc.modalPresentationStyle = .overFullScreen
present(vc, animated: true, completion: nil)
}
func push() {
let vc = NEXTHostingVC()
navigationController?
.pushViewController(vc, animated: true)
}
}
struct PREV: View {
@State private var isPresented = false
@State private var zstack = false
@State private var error = String?.none
@EnvironmentObject var route: PREVHostingVC.ROUTE
var body: some View {
VStack {
Button("Present SWIFTUI!") {
self.isPresented.toggle()
}
Button("Show UIKIT!") {
self.route.delegate?.show()
}
Button("Push UIKIt!") {
self.route.delegate?.push()
}
NavigationView {
NavigationLink(
"Push SwiftUI",
destination: NEXT(
text: "Push SwiftUI..."))
}
Button("ERROR!") {
self.error = "Just an error!"
}
Button("ZSTACK!") {
self.zstack.toggle()
}
ZStack(alignment: .bottom) {
EmptyView()
if zstack {
Text("Zstack shown")
}
}
}
// .onError(with: $error)
.onAppear(perform: {
print("ON APPEAR")
})
.sheet(isPresented: $isPresented) {
NEXT(text: "SHEET...")
}
}
}
protocol NEXTRouteDelegate: class {
func dismiss()
func pop()
}
final class NEXTHostingVC: UIHostingController<AnyView>, NEXTRouteDelegate, PanModalPresentable {
var panScrollable: UIScrollView? { nil }
class ROUTE: ObservableObject {
var delegate: NEXTRouteDelegate? = nil
init() {}
}
init() {
let route = ROUTE()
super.init(rootView: AnyView(NEXT(text:"NEXT HOSTING VC").environmentObject(route)))
route.delegate = self
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func dismiss() {
self.dismiss(animated: true, completion: nil)
}
func pop() {
navigationController?.popViewController(animated: true)
}
}
struct NEXT: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var route: NEXTHostingVC.ROUTE
let text: String
var body: some View {
VStack {
Text(text)
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Dismiss presentationMode")
}
Button(action: {
self.route.delegate?.dismiss()
}) {
Text("Dismiss NEXTHOSTINGVC")
}
Button(action: {
self.route.delegate?.pop()
}) {
Text("Pop NEXTHOSTINGVC")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.red)
.edgesIgnoringSafeArea(.all)
}
} Which I found this pattern to be super useful, especially for iOS 13 SwiftUI's which lack a lot of UIKit capabilities. (for me, this navigation system). For reloading using window.rootViewController = UINavigationController(
rootViewController: PREVHostingVC()
) |
From onAppeear
In theory, this should be triggered every time this view appears. But in practice, it is only called when it is pushed on navigation stack, not when we return to it.
So if user goes to a bookmark in a bookmark list, unbookmark an item and go back to the bookmark list,
onAppear
is not called again and the list is not updated.So instead of relying on UI state, we should rely on data state, by listening to
onReceive
and update our local@State
Inside our
ObservableObject
, we need to trigger changes notificationThe text was updated successfully, but these errors were encountered: