web-dev-qa-db-ja.com

2つのビュー間でのデータの受け渡し

WatchOS 6で静かなシンプルなアプリを作成したかったのですが、AppleがXcode 11ベータ5のObjectBindigを変更した後、アプリが実行されなくなりました。2つのビュー間でデータを同期したいだけです。

そのため、新しい@Publishedでアプリを書き直しましたが、実際には設定できません。

class UserInput: ObservableObject {

    @Published var score: Int = 0
}

struct ContentView: View {
    @ObservedObject var input = UserInput()
    var body: some View {
        VStack {
            Text("Hello World\(self.input.score)")
            Button(action: {self.input.score += 1})
                {
                    Text("Adder")
                }
            NavigationLink(destination: secondScreen()) {
                Text("Next View")
            }

        }

    }
}

struct secondScreen: View {
    @ObservedObject var input = UserInput()
    var body: some View {
        VStack {
            Text("Button has been pushed \(input.score)")
            Button(action: {self.input.score += 1
            }) {
                Text("Adder")
            }
        }

    }
}
2
Hansel

私の質問は2つのビュー間でデータを渡す方法に関連していますが、より複雑なJSONデータセットがあり、データの受け渡しと初期化の両方で問題が発生しています。動作するものがありますが、それが正しくないと確信しています。これがコードです。助けて!!!!

/ File: simpleContentView.Swift
import SwiftUI
// Following is the more complicated @ObservedObject (Buddy and class Buddies)
struct Buddy : Codable, Identifiable, Hashable {
    var id = UUID()
    var TheirNames: TheirNames
    var dob: String = ""
    var school: String = ""
    enum CodingKeys1: String, CodingKey {
        case id = "id"
        case Names = "Names"
        case dob = "dob"
        case school = "school"
    }
}
struct TheirNames : Codable, Identifiable, Hashable {
    var id = UUID()
    var first: String = ""
    var middle: String = ""
    var last: String = ""

    enum CodingKeys2: String, CodingKey {
        case id = "id"
        case first = "first"
        case last = "last"
    }
}

class Buddies: ObservableObject {
    @Published var items: [Buddy] {
        didSet {
            let encoder = JSONEncoder()
            if let encoded = try? encoder.encode(items) {UserDefaults.standard.set(encoded, forKey: "Items")}
        }
    }
    @Published var buddy: Buddy
    init() {
        if let items = UserDefaults.standard.data(forKey: "Items") {
            let decoder = JSONDecoder()
            if let decoded = try? decoder.decode([Buddy].self, from: items) {
                self.items = decoded
                // ??? How to initialize here
                self.buddy = Buddy(TheirNames: TheirNames(first: "c", middle: "r", last: "c"), dob: "1/1/1900", school: "hard nocks")
                return
            }
        }
        // ??? How to initialize here
        self.buddy = Buddy(TheirNames: TheirNames(first: "c", middle: "r", last: "c"), dob: "1/1/1900", school: "hard nocks")
        self.items = []
    }
}

struct simpleContentView: View {
    @Environment(\.presentationMode) var presentationMode
    @State private var showingSheet = true
    @ObservedObject var buddies = Buddies()
    var body: some View {
        VStack {
            Text("Simple View")
            Button(action: {self.showingSheet.toggle()}) {Image(systemName: "triangle")
            }.sheet(isPresented: $showingSheet) {
                simpleDetailView(buddies: self.buddies, item: self.buddies.buddy)}
        }
    }
}

struct simpleContentView_Previews: PreviewProvider {
    static var previews: some View {
        simpleContentView()
    }
}
// End of File: simpleContentView.Swift
// This is in a separate file: simpleDetailView.Swift
import SwiftUI

struct simpleDetailView: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var buddies = Buddies()
    var item: Buddy
    var body: some View {
        VStack {
            Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
            Text("First Name = \(item.TheirNames.first)")
            Button(action: {self.presentationMode.wrappedValue.dismiss()}){ Text("return"); Image(systemName: "gobackward")}
        }
    }
}
// ??? Correct way to make preview call
struct simpleDetailView_Previews: PreviewProvider {
    static var previews: some View {
        // ??? Correct way to call here
        simpleDetailView(item: Buddy(TheirNames: TheirNames(first: "", middle: "", last: ""), dob: "", school: "") )
    }
}
// end of: simpleDetailView.Swift
0
Charlie Cole

@State変数を直接使用すると、これを実現できますが、ビューモデルまたは@Publishedを使用して両方の画面でその変数を同期する場合は、これを実行できます。 @Stateは@Publishedプロパティにバインドされないためです。これを実現するには、次の手順に従います。

手順1:-ポップまたは非表示の値をバインドするデリゲートを作成します。

 protocol BindingDelegate {
     func updateOnPop(value : Int)
 }

ステップ2:-コンテンツビューのコードベースに従う

 class UserInput: ObservableObject {
      @Published var score: Int = 0
 }

 struct ContentView: View , BindingDelegate {

   @ObservedObject var input = UserInput()

   @State var navIndex : Int? = nil

   var body: some View {
       NavigationView {
          VStack {
              Text("Hello World\(self.input.score)")
              Button(action: {self.input.score += 1}) {
                    Text("Adder")
                }

            ZStack {
                NavigationLink(destination: secondScreen(score: self.$input.score,
                                                         del: self, navIndex: $navIndex),
                                                         tag: 1, selection: $navIndex) {
                    EmptyView()
                }

                Button(action: {
                    self.navIndex = 1
                }) {
                    Text("Next View")

                }
            }
        }
    }
}

   func updateOnPop(value: Int) {
       self.input.score = value
   }
}

ステップ3:secondScreenの以下のステップに従います

final class ViewModel : ObservableObject {

@Published var score : Int

   init(_ value : Int) {
       self.score = value
   }
}

struct secondScreen: View {

@Binding var score:  Int
@Binding var navIndex : Int?

@ObservedObject private var vm : ViewModel

var delegate  : BindingDelegate?

init(score : Binding<Int>, del : BindingDelegate, navIndex : Binding<Int?>) {
    self._score = score
    self._navIndex = navIndex
    self.delegate = del
    self.vm = ViewModel(score.wrappedValue)
}

private var btnBack : some View { Button(action: {
    self.delegate?.updateOnPop(value: self.vm.score)
    self.navIndex = nil
}) {
    HStack {
        Text("Back")
    }
    }
}

var body: some View {
    VStack {
        Text("Button has been pushed \(vm.score)")
        Button(action: {
            self.vm.score += 1
        }) {
            Text("Adder")
        }
    }
    .navigationBarBackButtonHidden(true)
    .navigationBarItems(leading: btnBack)

   }
}
0
Anshuman Singh