skip to Main Content
struct ProfileEditView: View {
    @ObservedObject var viewModel: UsersViewModel
    @StateObject var auth: Authenticator

    @State var showingImageEditor: Bool = false

    init(_ viewModel: UsersViewModel, _ auth: Authenticator) {
    
        self.viewModel = viewModel
        self.auth = auth
    
        UITableView.appearance().backgroundColor = UIColor.clear
        UITableViewCell.appearance().selectionStyle = .none
    }

    var body: some View { }
}

I am trying to manually intialize a view that takes a StateObject as a parameter. I am getting an error: Cannot assign to property: 'auth' is a get-only property. What is the proper way to write the initializer?

2

Answers


  1. 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.

    Login or Signup to reply.
  2. In addition to the ‘accepted answer’ there’s a really good example that will allow everyone to reproduce the error and understand how to avoid it.

    Considering there’s a viewModel in a View with a property wrapper @StateObject, there’s no need to initiate a StateObject(wrappedValue: ...) in the constructor as long as there are no private properties in the View. Let’s see an example:

    class MyViewModel: ObservableObject {}
    
    class MyView: View {
       @StateObject var viewModel: MyViewModel
    }
    

    The above example will work by simply using:

    MyView(viewModel: MyViewModel())
    

    But if we will add a private property to the View:

    class MyView: View {
       @StateObject var viewModel: MyViewModel
       // `test` will produce the protection level error
       private var test = false
    }
    

    Our previous example MyView(viewModel: MyViewModel()) will now produce the following error:

    initializer is inaccessible due to ‘private’ protection level

    So please consider why you declare a property in a View private, perhaps it can be moved to the ViewModel and the issue will be solved in order to utilize the dependency injection principle.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search