简体   繁体   中英

How To Perform a Segue on a Storyboard in a SwiftUI ViewModel File

Im currently injecting some SwiftUI view+viewModel files into a storyboard. The reasoning was so that in a future rewrite of the app to SwiftUI we already have some of the work done. In any case, I ended up creating a Hosting Controller , which injects my SwitfUI view file into the storyboard:

class LoginViewHostingController: UIHostingController<LoginView> {
    required init?(coder: NSCoder) {
        super.init(coder: coder,rootView: LoginView())
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

The problem is that the SwiftUI View file is using a ViewModel file (instance of ObservableObject) to perform a lot of its logic (mainly used for state).

struct LoginView: View  {
        
    @ObservedObject var loginVM = LoginViewModel()
    
    var body: some View {

...and then the view will use the loginVM like this:

                        if (!loginVM.showPasswordView) {
                            HStack {
                                Button(action: loginVM.checkEmailForSSOAuthentication) {
                                    Text("Next")
                                        .font(.system(.headline, design: .rounded))
                                        .foregroundColor(Color.white)
                                        .padding(.vertical, 18)
                                        .frame(width: 350)
                                        .background(Color("DigideckPrimary"))
                                        .cornerRadius(6)
                                }
                            }
                            .padding(.top, 10)
                        }

What I'm trying to do, just to confirm I can do it, is perform a segue on the storyboard that this SwiftUI view is injected in in this Next button's action ( loginVM.checkEmailForSSOAuthentication ) which I am not sure is possible.

I attempted this in my loginVM file:

    func checkEmailForSSOAuthentication() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let storyBoardLoginVc = storyboard.instantiateViewController(withIdentifier: "myLoginController")
        // instead of sending to self send to main storyboard if i can!
        storyBoardLoginVc.performSegue(withIdentifier: "test1", sender: self)
        return;

But receive the following error when this code executes:

2023-01-18 09:47:00.872611-0600 Digideck[35908:12697138] [Assert] UINavigationBar decoded as unlocked for UINavigationController, or navigationBar delegate set up incorrectly. Inconsistent configuration may cause problems. navigationController=<UINavigationController: 0x130879c00>, navigationBar=<UINavigationBar: 0x127e1ce70; frame = (0 0; 0 50); opaque = NO; autoresize = W; tintColor = UIExtendedSRGBColorSpace 0.0784314 0.392157 0.709804 1; gestureRecognizers = <NSArray: 0x6000010ab090>; layer = <CALayer: 0x600001ec0ea0>> delegate=0x130879c00
2023-01-18 09:47:00.873019-0600 Digideck[35908:12697138] [Presentation] Attempt to present <UINavigationController: 0x130879c00> on <Digideck.LoginViewHostingController: 0x10f00b600> (from <Digideck.LoginViewHostingController: 0x10f00b600>) whose view is not in the window hierarchy.

Which leads me to believe I instantiated a different storyboard rather than referencing the one already in view. If anyone knows if this is possible please let me know!

We don't use view model objects in SwiftUI so it's not the correct strategy to think you will be able to use them in UIKit and in SwiftUI. In SwiftUI the View struct is the view model already and the property wrappers like the @State give them reference type semantics, ie a view model object. Also this line is a mistake:

@ObservedObject var loginVM = LoginViewModel()

@ObservedObject has no ownership of the object so it is init and deinit with the View struct value type (every state change) so essentially you've created a memory leak. You need to use it like this:

@ObservedObject var model: Model

Where the Model has been init somewhere else like a singleton, or in the app delegate, ie it has an owner that is not a ephemeral struct value type.

I think it would be best to design your SwiftUI View to use @Binding var instead (if you need write access, otherwise just let ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM