斯威夫特,价值未更新
Posted
技术标签:
【中文标题】斯威夫特,价值未更新【英文标题】:Swift, value not updated 【发布时间】:2020-12-26 13:37:09 【问题描述】:在 Maze.swift 文件中,我有:
var myMaze = Maze() // -> 9.0
具有以下内容的 Maze 结构定义:
@State var widthDouble = 9.0
和 init() 方法
init()
print("Maze init:", self.widthDouble)
在 ContentView.swift 文件中,我有以下内容:
@State var widthDouble = myMaze.widthDouble
Slider(value: $widthDouble, in: 3...33, step: 1) // updated to 16.0
Button(action: action() ) Text("Build maze with updated values")
最后是 func action()
func action()
myMaze.widthDouble = widthDouble
print("ContentView: ", widthDouble) // -> 16.0
print("ContentView (myMaze.): ", myMaze.widthDouble) // -> 9.0
myMaze = .init()
虽然在 func action() 中 myMaze.widthDouble 被赋值为 widthDouble (16.0),但 myMaze.widthDouble 的值并没有更新,仍然是 9.0 !
init() 的输出: 迷宫初始化:9.0
滑块中的值 9.0 更新为 16.0
action() 的输出: 内容视图:16.0 内容视图(myMaze。):9.0
init() 的输出: 迷宫初始化:9.0
谁能告诉我哪里出了问题以及为什么 myMaze.widthDouble 没有更新?
文件 ContentView.swift
//
// ContentView.swift
// Maze
//
// Created by Philippe Lagarrigue on 24/12/2020.
//
import SwiftUI
struct ContentView: View
@State private var selectedTab = 0
let numTabs = 2
let minDragTranslationForSwipe: CGFloat = 50
var body: some View
TabView(selection: $selectedTab)
NavigationView
MenuView()
.navigationBarTitle("Settings")
.tabItem
Image("map")
Text("Map")
.tag(0)
.highPriorityGesture(DragGesture().onEnded(
self.handleSwipe(translation: $0.translation.width)
))
NavigationView
MenuView()
.navigationBarTitle("Settings")
.tabItem
Image("navigation")
Text("Navigation")
.tag(1)
.highPriorityGesture(DragGesture().onEnded(
self.handleSwipe(translation: $0.translation.width)
))
private func handleSwipe(translation: CGFloat)
if translation > minDragTranslationForSwipe && selectedTab > 0
selectedTab -= 1
else if translation < -minDragTranslationForSwipe && selectedTab < numTabs-1
selectedTab += 1
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
struct MenuView : View
@State var widthDouble = myMaze.widthDouble
@State var heightDouble = myMaze.heightDouble
@State var oneWay = myMaze.oneWay
@State private var isEditing1 = false
@State private var isEditing2 = false
//@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body : some View
HStack(alignment: VerticalAlignment.top)
VStack(alignment: .leading)
Text("Number of rooms (horizontally): \(widthDouble, specifier: "%.0f")")
.foregroundColor(isEditing1 ? .red : .black)
Slider(value: $widthDouble, in: 3...33, step: 1,
onEditingChanged: editing in isEditing1 = editing )
Divider()
// format: "Angle: %.0f", angle
Text("Number of rooms (vertically): \(heightDouble, specifier: "%.0f")")
.foregroundColor(isEditing2 ? .red : .black)
Slider(value: $heightDouble, in: 3...33, step: 1,
onEditingChanged: editing in isEditing2 = editing )
Divider()
Toggle("One way", isOn: $oneWay)
Button(action: action() ) Text("Build maze with updated values")
.padding()
func action()
myMaze.widthDouble = widthDouble
myMaze.heightDouble = heightDouble
print("ContentView: ", widthDouble, heightDouble)
print("ContentView (myMaze.): ", myMaze.widthDouble, myMaze.heightDouble)
myMaze = .init()
文件迷宫.swift
//
// Maze.swift
// NewMaze
//
// Created by Philippe Lagarrigue on 23/12/2020.
//
import Foundation
import SwiftUI
let wall = (North: 1, East: 2, South: 4, West: 8) // 15 means all walls
let exit = (toNorth: 16, toEast: 32, toSouth: 64, toWest: 128) // 0 means no exit
var myMaze = Maze()
struct Room
var x: Int
var y: Int
var roomsToExit: Int
struct Maze
// Properties
var width = 9
var height = 12
var widthDouble = 9.0
var heightDouble = 12.0
var oneWay = true
var exitRoom = Room(x: 0, y: 0, roomsToExit: 0)
var farestRoom = Room(x: 0, y: 0, roomsToExit: 0)
var mazeData = [[Int]]()
var numberOfRooms: Int return self.width * self.height
// Methods
init()
//print(self.widthDouble, self.heightDouble)
self.width = Int(self.widthDouble)
self.height = Int(self.heightDouble)
mazeData = Array(repeating: Array(repeating: 15, count: height), count: width)
print("Maze init:", self.width, "x", self.height)
【问题讨论】:
@State 仅用于在 UI 组件中更新的属性的视图中,因此您不应将其用于模型(?)类型中,例如 Maze。除此之外,我必须说很难理解您要做什么 谢谢你的答案,但你能告诉我如何在结构之外更新我的值Maze
和MazeBuilder
。我建议研究 ObservableObject
和 @Published
并将其用于您的构建器类。
【参考方案1】:
@State
用于视图内部的更改
@ObservedObject
用于存储ObservableObject
。
@Published
在@Published var
自身发生变化时发布。
有了这些知识,这就是答案。
import SwiftUI
struct ContentView: View
@State private var selectedTab = 0
let numTabs = 2
let minDragTranslationForSwipe: CGFloat = 50
var body: some View
TabView(selection: $selectedTab)
NavigationView
MenuView()
.navigationBarTitle("Settings")
.tabItem
Image("map")
Text("Map")
.tag(0)
.highPriorityGesture(DragGesture().onEnded(
self.handleSwipe(translation: $0.translation.width)
))
NavigationView
MenuView()
.navigationBarTitle("Settings")
.tabItem
Image("navigation")
Text("Navigation")
.tag(1)
.highPriorityGesture(DragGesture().onEnded(
self.handleSwipe(translation: $0.translation.width)
))
private func handleSwipe(translation: CGFloat)
if translation > minDragTranslationForSwipe && selectedTab > 0
selectedTab -= 1
else if translation < -minDragTranslationForSwipe && selectedTab < numTabs-1
selectedTab += 1
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
struct MenuView : View
@ObservedObject var myMaze = Maze()
@State private var isEditing1 = false
@State private var isEditing2 = false
//@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body : some View
HStack(alignment: VerticalAlignment.top)
VStack(alignment: .leading)
Text("Number of rooms (horizontally): \(myMaze.widthDouble, specifier: "%.0f")")
.foregroundColor(isEditing1 ? .red : .black)
Slider(value: $myMaze.widthDouble, in: 3...33, step: 1,
onEditingChanged: editing in isEditing1 = editing )
Divider()
// format: "Angle: %.0f", angle
Text("Number of rooms (vertically): \(myMaze.heightDouble, specifier: "%.0f")")
.foregroundColor(isEditing2 ? .red : .black)
Slider(value: $myMaze.heightDouble, in: 3...33, step: 1,
onEditingChanged: editing in isEditing2 = editing )
Divider()
Toggle("One way", isOn: $myMaze.oneWay)
Button(action: action() ) Text("Build maze with updated values")
.padding()
func action()
import Foundation
import SwiftUI
let wall = (North: 1, East: 2, South: 4, West: 8) // 15 means all walls
let exit = (toNorth: 16, toEast: 32, toSouth: 64, toWest: 128) // 0 means no exit
struct Room
var x: Int
var y: Int
var roomsToExit: Int
class Maze: ObservableObject
@Published var height = 12
@Published var widthDouble = 9.0
didSet
setMezData(height: Int(heightDouble), width: Int(widthDouble))
@Published var heightDouble = 12.0
didSet
setMezData(height: Int(heightDouble), width: Int(widthDouble))
@Published var oneWay = true
@Published var exitRoom = Room(x: 0, y: 0, roomsToExit: 0)
@Published var farestRoom = Room(x: 0, y: 0, roomsToExit: 0)
@Published var mazeData = [[Int]]()
didSet
print(mazeData)
var numberOfRooms: Int return Int(heightDouble) * Int(widthDouble)
func setMezData(height: Int, width: Int)
mazeData = Array(repeating: Array(repeating: 15, count: height), count: width)
【讨论】:
Thx,我按照建议更新了所有内容并且没有出现错误,但是 mazeData 数组没有用新值更新,你能告诉我如何更新它吗?将 放入 func action() 会给我以下错误:无法分配给属性:'self' is immutable 非常感谢大家,现在一切正常,我学到了很多! 在哪里可以找到这个勾号? @Swiftiti meta.stackexchange.com/questions/5234/…【参考方案2】:在你的帮助下,我终于找到了如何从其他类访问一个类的方法。
// MyClass definition
class MyClass: ObservableObject
static let sharedInstance = MyClass()
var myProperty = "Something"
...
// A struct where I need to use MyClass
struct MyView1 : View
@ObservedObject var ClassInst = MyClass.sharedInstance
...
ClassInst.myProperty = "Something else"
// Another struct where I need to use MyClass
struct MyView2 : View
@ObservedObject var ClassInst = MyClass.sharedInstance
...
ClassInst.myProperty = "Nothing"
【讨论】:
以上是关于斯威夫特,价值未更新的主要内容,如果未能解决你的问题,请参考以下文章
Xcode 6 Beta / Swift - Playground 未更新