在SwiftUI中,我该如何在init函数中初始化@State变量?

58

让我们看一下简单的源代码:

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!")
    }
}

我需要在这里使用init函数来进行一些数据加载,但是有一个问题,@State变量不能在此处初始化!我该怎么办? 也许这是一个非常简单的问题,但我不知道该怎么做。 非常感谢!

3个回答

92

属性包装器会为您生成一些代码。您需要知道的是实际生成的存储属性的类型是包装器的类型,因此您需要使用其构造函数,并且它以_为前缀。在您的情况下,这意味着var _mapState: State<Int>,因此按照您的示例:

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!")
    }
}

10
_mapState = 状态(initialValue: inputMapState) - Jason
1
那个下划线和.init函数解决了我的问题。这比在视图本身上使用.onAppear()更可取吗? - Manngo
似乎不应该像这样使用init(initialValue:)。该初始化程序可能仅用于ABI稳定性:https://forums.swift.org/t/swiftui-state-init-wrappedvalue-vs-init-initialvalue-whats-the-difference/38904 - 在某些情况下可能运行良好,但有时会表现奇怪。 - shim
1
警告:init 只会在第一次调用时被调用。如果 inputMapState 发生更改,您将看不到此视图的更新。 - joshuakcockrell

12

我们可以注入视图所需的数据。

使用一个具有访问所需数据的模型。创建地图视图并在父视图中使用该实例。这还将有助于对模型进行单元测试。

使用属性包装器@Binding将数据从父视图传递到MapView,并使用_mapState来保存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")
    }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接