62

Let's see the simple source code:

import SwiftUI

struct MyView: View {
    @State var mapState: Int
    
    init(inputMapState: Int)
    {
        mapState = inputMapState //Error: 'self' used before all stored properties are initialized
    } //Error: Return from initializer without initializing all stored properties
    
    var body: some View {
        Text("Hello World!")
    }
}

I need the init function here because I want to do some data loading here, but there is one problem, the @State variable could not be initialize here! How could I do with that? Maybe it's a very simple question, but I don't know how to do. Thanks very much!

3 Answers 3

99

Property wrappers are generating some code for you. What you need to know is the actual generated stored property is of the type of the wrapper, hence you need to use its constructors, and it is prefixed with a _. In your case this means var _mapState: State<Int>, so following your example:

import SwiftUI

struct MyView: View {
    @State var mapState: Int

    init(inputMapState: Int)
    {
        _mapState = /*State<Int>*/.init(initialValue: inputMapState)
    }

    var body: some View {
        Text("Hello World!")
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

_mapState = State(initialValue: inputMapState)
That uderscore and .init function solved my problem. Is this preferred over using .onAppear() on the view itself?
developer.apple.com/forums/thread/657393 etc. doesn't seem to be a good idea to use init(initialValue:) like this. That initializer may only be there for ABI stability: forums.swift.org/t/… — might work fine in some cases but behave strangely sometimes.
WARNING: The init will only be called the first time. If inputMapState changes, you won't see an update to this View.
12

We can inject the data that the view needs.

Used a model which has access to the data that you wanted. Make a map view and use that instance of it in your parent view. This will also help to unit test the model.

Used the property wrapper @Binding to pass the data from the parent view to MapView and used _mapState which holds the value of mapState.

struct Model {
 //some data
}

struct MapView {
    private let model: Model
    @Binding var mapState: Int

    init(model: Model, mapState: Binding<Int>) {
        self.model = model
        self._mapState = mapState
    }
}

extension MapView: View {

    var body: some View {
        Text("Map Data")
    }
}

Comments

1

I think that it would better to initialize when you write the code, just like:

@State var mapState = 0

or, if you want to binding the value with another view, use @Binding.

You have more information at https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-binding-property-wrapper

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.