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つのビュー間でデータを渡す方法に関連していますが、より複雑な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
@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)
}
}