斯威夫特,价值未更新

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。除此之外,我必须说很难理解您要做什么 谢谢你的答案,但你能告诉我如何在结构之外更新我的值 吗? 我刚刚删除了 State 并且可以正常编译,但值 仍然没有更新! 在更新属性后对迷宫变量调用 init() 有点奇怪。在我看来,您需要两种类型,一种迷宫模型和一种迷宫建造者,例如MazeMazeBuilder。我建议研究 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"

【讨论】:

以上是关于斯威夫特,价值未更新的主要内容,如果未能解决你的问题,请参考以下文章

Javascript - 变量失去其价值并“成为”未定义

Xcode 6 Beta / Swift - Playground 未更新

Laravel:下订单后更新股票价值

未初始化的价值和铿锵优化

我的道具在 React 的 ComponentDidMount 方法下的价值未定义

斯威夫特用户界面 |文本字段未读取输入的值