我\xe2\x80\x99在 SwiftUI 中遇到了与工作表演示相关的令人费解的行为。关闭工作表时,我注意到关联的实例(工作表\xe2\x80\x99s 视图持有的视图模型)don\xe2\x80\x99t 似乎已正确取消初始化。
\n根据我的测试,唯一deinit按预期被调用的场景是使用@StateObject. 相反,@ObservedObject新@Observable宏 don\xe2\x80\x99t 似乎都会触发调用deinit。
下面,我\xe2\x80\x99ve提供了一组展示各种场景的示例。每个尝试以不同的方式提供视图模型。要测试解雇,您只需在显示的工作表上向下滑动即可:
\nimport SwiftUI\n\n// ============================================================================ //\n// MARK: - App\n// ============================================================================ //\n\n@main\nstruct SwiftUISheetDeinitIssueApp: App {\n var body: some Scene {\n WindowGroup {\n CaseA_ContentView()\n }\n }\n}\n\n// ============================================================================ //\n// MARK: - Case A: @StateObject (Works!)\n// ============================================================================ //\n\nstruct CaseA_ContentView: View {\n @State var isPresented = false\n \n var body: some View {\n Button("Show Sheet") {\n self.isPresented = true\n }\n .sheet(isPresented: $isPresented) {\n CaseA_SheetView()\n …Run Code Online (Sandbox Code Playgroud) 我在 SwiftUI 中观察到的对象有问题。我可以在 View 结构上看到观察对象的变化值。但是在类或函数中,即使我更改了 TextField(可观察对象)的文本值,但“self.codeTwo.text 仍然没有改变。
这是我的代码示例(这是我的 ObservableObject)
class settingCodeTwo: ObservableObject {
private static let userDefaultTextKey = "textKey2"
@Published var text: String = UserDefaults.standard.string(forKey: settingCodeTwo.userDefaultTextKey) ?? ""
private var canc: AnyCancellable!
init() {
canc = $text.debounce(for: 0.2, scheduler: DispatchQueue.main).sink { newText in
UserDefaults.standard.set(newText, forKey: settingCodeTwo.userDefaultTextKey)
}
}
deinit {
canc.cancel()
}
}
Run Code Online (Sandbox Code Playgroud)
主要问题是......“self.codeTwo.text”从未改变!
class NetworkManager: ObservableObject {
@ObservedObject var codeTwo = settingCodeTwo()
@Published var posts = [Post]()
func fetchData() {
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = …Run Code Online (Sandbox Code Playgroud) 我尝试制作我的第一个 iOS 应用程序,但遇到以下问题,但我不明白如何解决它。我有一个选项卡式 MainPageView,我在其中加载所有数据,然后将其传递到不同的视图。当我在任务视图中添加新项目时,新项目会出现在列表中,但当发生某些情况(例如使用上下文菜单将任务标记为已完成)时,我也想更新任务视图
任务结构:
struct Task: Identifiable, Hashable {
var name: String = ""
var status: Bool = false
var notify: Bool = false
Run Code Online (Sandbox Code Playgroud)
MainPageView - 这里的任务位于 Firebase 观察下,因此当数据库中发生更改时它应该自动更新
struct MainPageView: View {
@State private var tasks: [Task] = []
...
var body: Some View{
TabView{
TaskPageView(tasklist: self.$tasks) ...
Run Code Online (Sandbox Code Playgroud)
任务页面视图
struct TaskPageView: View {
@Binding var tasklist: [Task]
...
var body: some View{
NavigationView{
List{
ForEach(self.tasklist, id:\.self){ task in
NavigationLink(destination: TaskDetView(task: task)){
TaskView(name: task.name, done: task.status, notify: task.notify).contextMenu{
Button(action: …Run Code Online (Sandbox Code Playgroud) 我一直在阅读 SwiftUI 中的属性包装器,我看到它们做得很好,但我真正不明白的一件事是@EnvironmentObject和@ObservedObject之间的区别。
从我到目前为止所学到的,我看到@EnvironmentObject在我们的应用程序的各个地方都需要一个对象时使用,但我们不需要通过所有这些地方传递它。例如,如果我们有层次结构 A -> B -> C -> D 并且对象是在 A 处创建的,那么它会保存在环境中,以便我们可以将它直接从 A 传递到 D,如果 D 需要的话。
如果我们使用在 A 创建并需要传递给 D 的@ObservedObject,那么我们也需要通过 B 和 C。
但我仍然不知道如何决定使用哪一个。以下是我制作的 2 个示例项目:
struct ContentView2: View {
var order = Order2()
var body: some View {
VStack {
EditView2()
DisplayView2()
}
.environmentObject(order)
}
}
struct EditView2: View {
@EnvironmentObject var user: Order2
var body: some View {
HStack{
TextField("Fruit", text: $user.item)
}
}
}
struct …Run Code Online (Sandbox Code Playgroud) 我有一个视图和一个 viewModel,当用户添加到用户数组时,它们应该更新 ListView。我可以验证是否已添加用户,但 ObservedObject 并未更新。
我有一个搜索栏,可让您搜索用户,然后更新 ViewModel 中的用户数组,该数组应该更新视图,但事实并非如此。
视图模型
class UsersViewModel: ObservableObject {
@Published var users: [User] = []
@Published var isLoading = false
var searchText: String = ""
func searchTextDidChange() {
isLoading = true
API.User.searchUser(text: searchText) { (users) in
self.isLoading = false
self.users = users
}
// confirmed that users has data now at this point
}
}
Run Code Online (Sandbox Code Playgroud)
看法
struct UsersView: View {
@ObservedObject var usersViewModel = UsersViewModel()
var body: some View {
VStack() {
SearchBarView(text: $usersViewModel.searchText, onSearchButtonChanged: usersViewModel.searchTextDidChange) …Run Code Online (Sandbox Code Playgroud) 我已经在 SwiftUI 的问题上苦苦挣扎了几个小时。
这是我的问题的一个简化示例:
class Parent: ObservableObject {
@Published var children = [Child()]
}
class Child: ObservableObject {
@Published var name: String?
func loadName() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// Async task here...
self.objectWillChange.send()
self.name = "Loaded name"
}
}
}
struct ContentView: View {
@ObservedObject var parent = Parent()
var body: some View {
Text(parent.children.first?.name ?? "null")
.onTapGesture {
self.parent.objectWillChange.send()
self.parent.children.first?.loadName() // does not update
}
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个 ObservableObject(父级),存储 ObservableObjects(子级)的 @Published 数组。
问题是,当通过数组中一个对象上的异步任务更改名称属性时,视图不会更新。
你有什么主意吗 ?
非常感谢尼古拉斯
我有一个 ObservableObject 类,Model0它有一个Publishedobject nested。该nested对象表示一个递归树结构。我希望能够更新树结构并适当更新 UI。但是,在下面的代码中,当我更新对象的子对象时nested,UI 不会更新,我认为是因为对对象的引用nested没有更改。nested当我更改树结构中的任何对象时,如何更新 UI ?
class Nested: Identifiable {
var id: UUID = UUID()
var name: String
var children:[Nested]
init(name: String, children:[Nested]) {
self.children = children
self.name = name
}
}
class Model0 : ObservableObject {
@Published var nested: Nested
init(nested: Nested) {
self.nested = nested
}
func update() {
nested.children[0] = Nested(name:"New", children: [])
}
}
struct NestedView: View {
var nested: Nested …Run Code Online (Sandbox Code Playgroud) 当我在 Google 上搜索“State vs ObservedObject”时,第一个结果来自 Hacking with Swift,它说@ObservedObject:
这与@State 非常相似,除了现在我们使用的是外部引用类型,而不是像字符串或整数这样的简单本地属性。
我可以@ObservedObject用来创建持久化状态吗?它是否像简单@State属性和@ObservedObject复杂对象一样简单,还是有更多细微差别?
我了解如何使用 @EnvironmentObject 使全局数据可用于任何视图类,但我找不到将变量传递给非视图类的方法。
我的情况似乎是一个常见问题,是:
let contentView = ContentView()
.environmentObject(UserSettings())
Run Code Online (Sandbox Code Playgroud)
struct HomeView: View {
@EnvironmentObject var user: UserSettings <=== ACCESS TO GLOBAL DATA
@ObservedObject var categories = Categories() <=== GET DATA FOR THIS VIEW
var body: some View {
...
}
Run Code Online (Sandbox Code Playgroud)
class Categories : ObservableObject {
@Published var allCategories = CategoriesModel()
@EnvironmentObject var user: UserSettings <==== CANNOT ACCESS THIS DATA!
init() { …Run Code Online (Sandbox Code Playgroud) 为了提供一些背景信息,我正在编写我们应用程序的订单跟踪部分,该部分会经常从服务器重新加载订单状态。屏幕上的 UI 是用 SwiftUI 开发的。我需要屏幕上有一个可选图像,该图像随着订单的进展而变化。
当我尝试以下操作时,一切正常......
我的 viewModel 是一个 ObservableObject:
internal class MyAccountOrderViewModel: ObservableObject {
这有一个已发布的属性:
@Published internal var graphicURL: URL = Bundle.main.url(forResource: "tracking_STAGEONE", withExtension: "gif")!
在 SwiftUI 中使用该属性如下:
GIFViewer(imageURL: $viewModel.graphicURL)
我的问题是该graphicURL属性的占位符值可能不正确,而我的要求是它是可选的。将已发布的属性更改为:@Published internal var graphicURL: URL?会导致我的 GIFViewer 出现问题,它不接受可选 URL:
Cannot convert value of type 'Binding<URL?>' to expected argument type 'Binding<URL>'
尝试明显展开 会graphicURL产生此错误:
Cannot force unwrap value of non-optional type 'Binding<URL?>'
使这项工作有效的正确方法是什么?我不想在属性中添加一个值,并检查该属性是否等于占位符值(即将其视为 nil),或者假设该属性始终为非 nil 并以某种方式不安全地强制解开它。
observedobject ×10
swiftui ×10
combine ×2
swift ×2
binding ×1
children ×1
ios ×1
observable ×1
tree ×1
xcode ×1