首页 > 解决方案 > How Should My Code Run When using SwiftUI And Websockets

问题描述

I am making a client that connect to a websocket and shows different pages. I am looking for help on how I should order my code. First the user logs in and it connects them to the websocket to verify and if they are authorized it will continue, if not it will show an error.

TLDR My code need to somehow connect to a websocket, go to a new page, and show info. My code also needs to alert the user about any errors.

var request = URLRequest(url: URL(string: "wss://link")!)
struct LoginView: View {
    @State private var loggedIn = false
    @State private var loginCode = ""
    var body: some View {
        NavigationView {
            VStack(spacing: 30) {
                NavigationLink(destination: newView().navigationBarHidden(true), isActive: $loggedIn) { EmptyView() }
                HStack {
                  Image(systemName: "person").foregroundColor(.gray)
                  TextField("Login Code", text: $loginCode)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                  }
                .frame(width: 300)
                .offset(y: -75)
                })
                .buttonStyle(ContainedButtonStyle())
                .offset(y: -50)
            }
            .navigationBarTitle("Log In")
        }
        
    }
}
func connectToSocket(loginCode: String) {
    request.addValue("Bearer \(loginCode)", forHTTPHeaderField: "Authorization")
    let ws = WebSocket(request: request)
    struct newView: View {
        @State private var accountsCheckedShown = false
        let username = "MarcoD1337"
        let games = 5
        let lives = 10
        let money = "$5/$5"
        let status = "Ready For Cashout"
        var body: some View {
            NavigationView {
                TabView {
                    ZStack {
                        List{
                            HStack {
                                ZStack {
                                    Circle().fill(Color(red: 0.913, green: 0.737, blue: 0.447, opacity: 1))
                                        .frame(maxWidth: 50, maxHeight: 50)
                                    Text("")
                                        .font(.largeTitle)
                                        .multilineTextAlignment(.center)
                                }
                                VStack(alignment: .leading) {
                                    Text(username)
                                        .font(.title)
                                        .fontWeight(.bold)
                                        .minimumScaleFactor(0.25)
                                    Text("Games: \(games)")
                                        .minimumScaleFactor(0.5)
                                    Text("Lives: \(lives)")
                                        .minimumScaleFactor(0.5)
                                    Text("\(money) Available")
                                        .minimumScaleFactor(0.5)
                                    Text("Status: \(status)")
                                        .minimumScaleFactor(0.5)
                                }
                                    .padding()
                            }
                        }
                        .navigationTitle("Accounts")
                    }
                    .tabItem {
                        Image(systemName: "star")
                        Text("User Info")
                    }
                }
            }
        }
    }
    ws.event.open = { }
    ws.event.message = { message in
        let msg = JSON(message)
        if msg["type"] == "" { }
    }
    ws.event.error = { error in
        //errorLoginView(error: "\(error)")
    }
}

标签: swiftswiftui

解决方案


I've used WebSocket(StarScream) in a Swift demo app.

I'd recommend using a standalone state object (@ObservableObject or @EnvironmentObject)to handle websocket. Think of it as a shared websocket service.

In this service, you publish a couple of events based on your needs.

E.g.;

enum LoginState {
    case initial, authOK, authFail
}

final class Websocket: ObservableObject {
    @Published var state: LoginState = .initial
    // implement websocket callbacks
    // e.g.; change state to .authFail in error handler 
}

Your LoginView simply observes state changes:

struct LoginView: View {
    @ObservedObject var ws = Websocket()
    var body: some View {
        // setup websocket as needed
        switch ws.state { // supported in Xcode 12 as I recall, use if otherwise
        case .authOK:
            // some view
        // other cases
        }
    }
 }

This is the overall picture, you need to fill in the implementation yourself.

I think this is sufficient to get you started on the right track.


推荐阅读