gpt4 book ai didi

SwiftUI如何防止 View 重新加载整个 body

转载 作者:行者123 更新时间:2023-12-03 09:19:57 24 4
gpt4 key购买 nike

基本上我试图弄清楚我的 viewModel 何时更新,它会通知 View 并刷新整个 body 。如何避免这种情况。例如,如果我的 View GoLiveView 已经呈现另一个 View BroadcasterView,然后我的 goLiveViewModel 得到更新,GoLiveView 将被刷新,它会再次创建 BroadcasterView,因为 showBroadcasterView = true。正因为如此,它会导致很多问题。

struct GoLiveView: View {

@ObservedObject var goLiveViewModel = GoLiveViewModel()
@EnvironmentObject var sessionStore: SessionStore
@State private var showBroadcasterView = false
@State private var showLiveView = false

init() {
goLiveViewModel.refresh()
}

var body: some View {
NavigationView {
List(goLiveViewModel.rooms) { room in // when goLiveViewModed get updated
NavigationLink(destination: LiveView(clientRole: .audience, room: room, showLiveView: $showLiveView))) {
LiveCell(room: room)

}
}.background(Color.white)
.navigationBarTitle("Live", displayMode: .inline)
.navigationBarItems(leading:
Button(action: {
self.showBroadcasterView = true
}, label: {
Image("ic_go_live").renderingMode(.original)
})).frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(red: 34/255, green: 34/255, blue: 34/255))

.sheet(isPresented: $showBroadcasterView) { // here is problem, get called many times, hence reload whole body ,and create new instances of BroadcasterView(). Because showBroadcasterView = is still true.

BroadcasterView(broadcasterViewModel: BroadcasterViewModel(showBroadcasterView: $showBroadcasterView))
.environmentObject(self.sessionStore)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.clear)
}

}
}

这是我的 GoliveViewModel

typealias RoomsFetchOuput = AnyPublisher<RoomsFetchState, Never>

enum RoomsFetchState: Equatable {

static func == (lhs: RoomsFetchState, rhs: RoomsFetchState) -> Bool {
switch (lhs, rhs) {
case (.loading, .loading): return true
case (.success(let lhsrooms), .success(let rhsrooms)):
return lhsrooms == rhsrooms
case (.noResults, .noResults): return true
case (.failure, .failure): return true
default: return false
}
}

case loading
case success([Room])
case noResults
case failure(Error)
}

class GoLiveViewModel: ObservableObject {

private lazy var webServiceManager = WebServiceManager()
@Published var rooms = [Room]()
private lazy var timer = Timer()
private var cancellables: [AnyCancellable] = []

init() {
timer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(refresh) , userInfo: nil, repeats: true) // call every 4 second refresh
}

func fetch() -> RoomsFetchOuput {
return webServiceManager.fetchAllRooms()
.map ({ result -> RoomsFetchState in
switch result {
case .success([]): return .noResults
case let .success(rooms): return .success(rooms)
case .failure(let error): return .failure(error)
}
})
.eraseToAnyPublisher()

let isLoading: RoomsFetchOuput = .just(.loading)
let initialState: RoomsFetchOuput = .just(.noResults)

let idle: RoomsFetchOuput = Publishers.Merge(isLoading, initialState).eraseToAnyPublisher()

return Publishers.Merge(idle, rooms).removeDuplicates().eraseToAnyPublisher()

}

@objc func refresh() {
cancellables.forEach { $0.cancel() }
cancellables.removeAll()
fetch()
.sink { [weak self] state in
guard let self = self else { return }
switch state {
case let .success(rooms):
self.rooms = rooms
case .failure: print("failure")
// show error alert to user
case .noResults: print("no result")
self.rooms = []
// hide spinner
case .loading: print(".loading")
// show spinner
}
}
.store(in: &cancellables)
}
}

最佳答案

SwfitUI 对此有一个模式。它需要使自定义 View 符合 Equatable协议(protocol)

struct CustomView: View, Equatable {

static func == (lhs: CustomView, rhs: CustomView) -> Bool {
// << return yes on view properties which identifies that the
// view is equal and should not be refreshed (ie. `body` is not rebuilt)
}
...
并代替构造添加修饰符 .equatable() , 像
var body: some View {
CustomView().equatable()
}
是的, CustomView 的新值每次都将构造为 super View 刷新(所以不要使 init 重),但是 body将被称为 仅当新构建的 View 不等于先前构建的
最后,可以看出将 UI 层次结构分解为多个 View 非常有用,它将允许优化刷新很多(但不仅是良好的设计、可维护性、可重用性等 :^))。
backup

关于SwiftUI如何防止 View 重新加载整个 body ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60482098/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com