Как избежать вызова init () на листе, когда родительский вид обновлен в SwiftUI - PullRequest
0 голосов
/ 12 марта 2020

TestView3 может отображать 2 листа: TestView4 и TestView5. TestView4 имеет значение @State, которое инициализируется из TestView3. TestView5 имеет значение @ObservedObject, которое также инициализируется из TestView3.

Когда я переключаю глобальное значение (global.on), он обновляет TestView3, а затем вызывает TestView4 или TestView5 init ().

Q1. Как избежать вызова init () в TestView4 или TestView5 при обновлении TestView3? Как полностью изолировать вид с листа от вида? Или любое обновление в представлении повлияет на лист, это ужасно.

Q2. Поведения init () в TestView4 или TestView5 не одинаковы. Локальный @State в TestView4 НЕ будет изменен в init (). Но локальный @ObservedObject будет изменен в init (). Почему? Это так странно. Как сделать так, чтобы @ObservedObject НЕ изменялось в init () из-за обновления TestView3?

Вы можете протестировать следующий код, журнал трассировки такой странный.

class Global: ObservableObject {
    static let shared = Global()
    @Published var on: Bool = false
}

class Local: ObservableObject {
    @Published var on: Bool = false
    init(_ on: Bool) {
        self.on = on
    }
}

struct TestView3: View {
    @ObservedObject var global = Global.shared
    @State private var sheetShowing = false
    @State private var sheetShowingId = 4
    var body: some View {
        print("test view3 body, glabel on = \(global.on)"); return
        VStack {
            Text("Global").foregroundColor(global.on ? .red : .gray).onTapGesture {
                self.global.on.toggle()
            }.padding()
            Button(action: {
                self.sheetShowing = true
                self.sheetShowingId = 4
                print("test view3, will show test view4")
            }) { Text("Show TestView4") }.padding()
            Button(action: {
                self.sheetShowing = true
                self.sheetShowingId = 5
                print("test view3, will show test view5")
            }) { Text("Show TestView5") }.padding()
        }.sheet(isPresented: $sheetShowing) {
            if self.sheetShowingId == 4 {
                TestView4(on: self.global.on)
            } else {
                TestView5(on: self.global.on)
            }
        }
    }
}

struct TestView4: View {
    @State private var on: Bool
    init(on: Bool) {
        self._on = State(initialValue: on)
        print("test view4 init, glabel on = \(Global.shared.on), local on = \(self.on)")
    }
    var body: some View {
        print("test view4 body, glabel on = \(Global.shared.on), local on = \(on)"); return
        VStack {
            Text("TestView4").padding()
            Text("Local").foregroundColor(on ? .red : .gray).onTapGesture {
                self.on.toggle()
                print("test view4, local toggle")
            }.padding()
            Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
                Global.shared.on.toggle()
                print("test view4, global toggle")
            }.padding()
        }
    }
}

struct TestView5: View {
    @ObservedObject var local: Local
    init(on: Bool) {
        self._local = ObservedObject(initialValue: Local(on))
        print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
    }
    var body: some View {
        print("test view5 body, glabel on = \(Global.shared.on), local on = \(local.on)"); return
        VStack {
            Text("TestView5").padding()
            Text("Local").foregroundColor(local.on ? .red : .gray).onTapGesture {
                self.local.on.toggle()
                print("test view5, local toggle")
            }.padding()
            Text("Global").foregroundColor(Global.shared.on ? .red : .gray).onTapGesture {
                Global.shared.on.toggle()
                print("test view5, global toggle")
            }.padding()
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 15 марта 2020

Наконец-то я нашел причину.

@ ObservedObject отличается от @State. Apple делает некоторые специальные работы на @State. @State будет храниться в специальном пространстве независимо от вида.

@ ObservedObject будет инициализироваться каждый раз при обновлении пользовательского интерфейса. он не может восстановить значение как @ State.

Итак, используя @State вместо @ ObservedObject.

0 голосов
/ 13 марта 2020

Q1: Вы не можете этого избежать . Почему? Каждый раз, когда значение свойства TestView3, заключенного в State или ObservedObject, изменяется, оно пересчитывает свое тело. Даже в случае, если TestView3 или TestView4 будут зависеть от этих значений, эта часть объявления

if self.sheetShowingId == 4 {
    TestView4(on: self.global.on)
} else {
    TestView5(on: self.global.on)
}

представляет одно представление, и его тело должно быть переоценено.

Q2: Это не простой ответ, просто потому что мы не знаем слишком много о деталях реализации друг друга. По крайней мере, я предлагаю вам не зависеть от вашего расследования :-). Так или иначе, легко увидеть, что вы создаете новую (локальную копию) вашей модели Local () в TestView5.init.

init(on: Bool) {
    self._local = ObservedObject(initialValue: Local(on))
    print("test view5 init, glabel on = \(Global.shared.on), local on = \(self.local.on)")
}

Вам действительно нравится иметь другую (независимую) модель каждый раз, когда SwiftUI необходимо обновить sh своих видов? Я так не думаю ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...