Initialize @Stateobject With a Parameter in Swiftui

Initialize @StateObject with a parameter in SwiftUI

Here is a demo of solution. Tested with Xcode 12b.

class MyObject: ObservableObject {
@Published var id: Int
init(id: Int) {
self.id = id
}
}

struct MyView: View {
@StateObject private var object: MyObject
init(id: Int = 1) {
_object = StateObject(wrappedValue: MyObject(id: id))
}

var body: some View {
Text("Test: \(object.id)")
}
}

backup

Initialize StateObject with another StateObject

Try the following

@main
struct DuneApp: App {
@StateObject var userManager: UserManager
@StateObject var appearancesStore: AppearancesStore
@StateObject var behavioursStore: BehavioursStore

init() {
let userManager = UserManager()

_userManager = StateObject(wrappedValue: userManager)
_appearancesStore = StateObject(wrappedValue: AppearancesStore(manager: userManager))
_behavioursStore = StateObject(wrappedValue: BehavioursStore(manager: userManager))
}

var body: some Scene {
WindowGroup {
AuthenticateView()
.environmentObject(userManager)
.environmentObject(appearancesStore)
.environmentObject(behavioursStore)
}
}
}

How to initialize a view with a stateobject as a parameter?

I can't fully reproduce your code without your definitions of Authenticator and UsersViewModel, but I got it to compile:

class UsersViewModel: ObservableObject {}
class Authenticator: ObservableObject {}

struct ProfileEditView: View {
@ObservedObject var viewModel: UsersViewModel
@StateObject var auth: Authenticator

@State var showingImageEditor: Bool = false

init(_ viewModel: ObservedObject<UsersViewModel>, _ auth: Authenticator) {

_viewModel = viewModel
_auth = StateObject(wrappedValue: auth)

UITableView.appearance().backgroundColor = UIColor.clear
UITableViewCell.appearance().selectionStyle = .none
}

var body: some View {
Text("something")
}
}

These are the key changes:

init(_ viewModel: ObservedObject<UsersViewModel>, _ auth: Authenticator) {
_viewModel = viewModel
_auth = StateObject(wrappedValue: auth)

If you don't understand my changes you should google

"swift property wrappers"

to get a better understanding of what property wrappers are and how to use them.

SwiftUI: How to initialize a new StateObject in a parent view?

As mentioned in the comments already, the route you probably want to take is reseting the state within the same WorkoutManager. You wouldn't be able to assign a new object to a @StateObject anyway -- you'll end up with compiler errors because of the View's immutable self.

Secondly, I'd suggest that you probably don't want to rely on the Button in your WorkoutView to do this. For example, if the user dismissed the sheet by swiping, that wouldn't get called. Instead, you could listen for the sheet's state in onChange (another method would be using the onDismiss parameter of sheet):

class WorkoutManager: ObservableObject {
var workout: HKWorkout?

func resetState() {
//do whatever you need to do to reset the state
print("Reset state")
}
}

struct ContentView: View {

@StateObject var workoutManager = WorkoutManager()

@State var showingWorkoutView = false

var body: some View {

Button {
showingWorkoutView.toggle()
} label: {
Text("Start Workout")
}
.sheet(isPresented: $showingWorkoutView) {
WorkoutView(showingWorkoutView: $showingWorkoutView)
}
.onChange(of: showingWorkoutView) { newValue in
if !newValue {
workoutManager.resetState()
}
}
}
}

struct WorkoutView: View {

@EnvironmentObject var workoutManager: WorkoutManager
@Binding var showingWorkoutView: Bool

var body: some View {
Text("Workout Started")
.padding()
Button {
showingWorkoutView.toggle()
} label: {
Text("End Workout")
}

}
}

StateObject as parameter for another object in init()

Use computed property

struct Test: App {

@StateObject var user: User = User()
var authenticationHelper: AuthenticationHelper {
return AuthenticationHelper(user: user)
}

init() {
}
}

You can also use like this

struct Test: App {

@StateObject var user: User
var authenticationHelper: AuthenticationHelper

init() {
let user = User()
self._user = StateObject(wrappedValue: user)
self.authenticationHelper = AuthenticationHelper(user: user)
}
}

Need data to initialize a StateObject

I believe you are trying to use these properties inside a View.

To solve your problem, you can simply split your code in two different views, where in the first one you define the SettingsStore instance, then you use it to initialise the Matrix instance of the second view.

Like this:

struct FirstView: View {
@State private var settingsStore = SettingsStore()

var body: some View {
SubView(settingsStore: $settingsStore, matrix: Matrix(d: settingsStore.d))
}
}

struct SubView: View {
@Binding var settingsStore: SettingsStore
@StateObject var matrix: Matrix

var body: some View {
Text(matrix.d)
}

}

Inject a StateObject into SwiftUI View

The latest version of Resolver supports @InjectedObject property wrapper for ObservableObjects. This wrapper is meant for use in SwiftUI Views and exposes bindable objects similar to that of SwiftUI @ObservedObject and @EnvironmentObject.

I am using it a lot now and its very cool feature.

eg:

class AuthService: ObservableObject {

@Published var isValidated = false

}

class LoginViewModel: ObservableObject {

@InjectedObject var authService: AuthService

}

Note: Dependent service must be of type ObservableObject. Updating object state will trigger view update.



Related Topics



Leave a reply



Submit