标签: observableobject

为什么在 SwiftUI 中的 TextField 绑定上调用 didSet 两次?

我有一个非常基本的视图,仅显示TextField

看法

struct ContentView: View {

    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        TextField("Enter a string...", text: $viewModel.string)
    }
    
}
Run Code Online (Sandbox Code Playgroud)

TextField文本绑定到string视图模型上的属性:

视图模型

class ViewModel: ObservableObject {
    
    @Published var string: String = "" {
        didSet {
            print("didSet string:", string)
        }
    }
    
}
Run Code Online (Sandbox Code Playgroud)

我添加了一个didSet属性观察器,以便在字符串更改时执行自定义操作。对于这个简单的例子,我只在控制台上打印一个字符串。

观察

当我运行此代码并在文本字段中输入字符串“123”时,这是我得到的输出:

didSet string: 1
didSet string: 1
didSet string: 12
didSet string: 12
didSet string: 123
didSet string: 123
Run Code Online (Sandbox Code Playgroud)

问题:

为什么?
为什么didSet我输入的每个字符都会调用两次闭包?(我希望每个角色都会调用一次。)

代码有什么问题或者这是预期的行为吗?

binding textfield property-observer swiftui observableobject

25
推荐指数
2
解决办法
1561
查看次数

SwiftUI 视图不基于@ObservedObject 更新

在下面的代码中,观察到的对象被更新,但观察它的视图没有更新。知道为什么吗?

代码在屏幕上显示 10 个数字 (0..<10) 和一个按钮。每当按下按钮时,它会随机选择 10 个数字之一并翻转其可见性(可见?隐藏,反之亦然)。

打印语句显示按钮正在更新数字,但视图不会相应更新。我知道更新数组中的值不会改变数组值本身,所以我使用手册objectWillChange.send()调用。我原以为应该触发更新,但屏幕永远不会改变。

任何的想法?我对NumberLine用作类或结构的解决方案感兴趣,或者根本不使用NumberLine类型,而只是在ContentView结构中使用数组变量。

截屏

这是代码:

import SwiftUI

struct ContentView: View {

    @ObservedObject var numberLine = NumberLine()

    var body: some View {
        VStack {
            HStack {
                ForEach(0 ..< numberLine.visible.count) { number in
                    if self.numberLine.visible[number] {
                        Text(String(number)).font(.title).padding(5)
                    }
                }
            }.padding()

            Button(action: {
                let index = Int.random(in: 0 ..< self.numberLine.visible.count)
                self.numberLine.objectWillChange.send()
                self.numberLine.visible[index].toggle()
                print("\(index) now \(self.numberLine.visible[index] ? "shown" : "hidden")")
            }) {
                Text("Change")
            }.padding()
        }
    }
}

class NumberLine: ObservableObject …
Run Code Online (Sandbox Code Playgroud)

arrays ios swiftui observableobject

20
推荐指数
3
解决办法
2万
查看次数

SwiftUI - ObservableObject 创建了多次

我在视图中创建了一个 ObservableObject。

@ObservedObject var selectionModel = FilterSelectionModel()
Run Code Online (Sandbox Code Playgroud)

我在FilterSelectionModel'sinit函数中放置了一个断点,并多次调用它。因为这个 View 是 a 的一部分NavigationLink,所以我知道它是在那时创建的,并且与它一起创建, selectionModel 。当我导航到视图时,将再次创建 selectionModel。

在同一个视图中,我有一个“子视图”,我将 selectionModel 作为一个传递给子视图,EnvironmentObject以便子视图可以更改它。

AddFilterScreen().environmentObject(self.selectionModel)
Run Code Online (Sandbox Code Playgroud)

当子视图被关闭时,selectionModel 将再次创建并且对它所做的更改也消失了。

有趣的提示:在最顶层是一个NavigationView. 如果我添加

.navigationViewStyle(StackNavigationViewStyle())
Run Code Online (Sandbox Code Playgroud)

对此NavigationView,我的 selectionModel 的变化消失了。但是,如果我添加navigationStyle,则子视图中的 selectionModel 更改仍然存在!!(但我不想要拆分导航视图,我想要堆叠的导航视图)

在这两种情况下 - 有或没有navigationStyle, selectionModel 都会被创建多次。我无法理解这些应该如何可靠地工作。

navigationview swiftui observableobject

14
推荐指数
2
解决办法
2495
查看次数

Actor 隔离 @Observable 类型

回到 WWDC 2021\xe2\x80\x99s Discover concurrency in SwiftUI,他们建议您将ObservableObject对象与主要参与者隔离。例如:

\n
struct ContentView: View {\n    @StateObject var viewModel = ViewModel()\n\n    var body: some View {\n        Text("\\(viewModel.count)")\n        .task {\n            try? await viewModel.start()\n        }\n    }\n}\n\n@MainActor \nclass ViewModel: ObservableObject {\n    var count = 0\n\n    func start() async throws {\n        while count < 10 {\n            count += 1\n            try await Task.sleep(for: .seconds(1))\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但在 iOS 17\xe2\x80\x99s观察框架(如 WWDC 2023\xe2\x80\x99s Discover Observation in SwiftUI中介绍)中,似乎不再需要隔离到主要参与者来防止在后台线程。例如,以下内容不会出现有关从后台启动 UI 更新的警告:

\n
struct ContentView: View {\n …
Run Code Online (Sandbox Code Playgroud)

ios swift observableobject ios17 observation-framework

10
推荐指数
1
解决办法
1169
查看次数

SwiftUI - 更改@Published 结构时是否可以触发 didSet?

我刚刚更新到 XCode 11.4,我的一些代码已经停止工作。我@Published在一个ObservableObject. 以前,当我更新结构上的属性时,该didSet方法会触发已发布的属性,但现在情况不再如此。在 Swift 的最新更新中,这种行为是否有可能被设计改变了?

这是一个简单的例子:


import SwiftUI

struct PaddingRect {
  var left: CGFloat = 20
  var right: CGFloat = 20
}

final class SomeStore : ObservableObject {
  @Published var someOtherValue: String = "Waiting for didSet"

  @Published var paddingRect:PaddingRect = PaddingRect() {
    didSet {
      someOtherValue = "didSet fired"
    }
  }
}

struct ObserverIssue: View {
  @ObservedObject var store = SomeStore()

  var body: some View {
    VStack {
      Spacer()

      Rectangle()
        .fill(Color.yellow)
        .padding(.leading, store.paddingRect.left)
        .padding(.trailing, …
Run Code Online (Sandbox Code Playgroud)

ios swift swift5 swiftui observableobject

9
推荐指数
2
解决办法
6132
查看次数

SwiftUI ForEach 未更新 ObservableObject 类数组的更改

背景

在我的应用程序中,我有一系列可以从另一个视图添加的朋友。我已将这组朋友存储在一个类中,该类是ObservableObject. 在我的主视图中FriendListView,我使用ForEach为用户添加的每个朋友显示自定义视图。

我无法添加到数组并让列表显示新项目。根据我能够理解和组合的内容,我尝试了两种不同的尝试。如果有人能够提供任何帮助,我们将不胜感激。我目前有显示第二个视图的方法,我将在其中添加注释掉的新朋友,并且有一种自动保存新朋友的方法作为导航栏项目存在。

尝试

尝试#1

如果在类初始值设定项期间将朋友列表附加到数组中,我就成功地显示了朋友列表。调用类方法从另一个视图添加到数组似乎是可行的,因为我能够打印数组的内容,但 UI 不会更新。

这是通过使用一种ForEach(0..<Array.count)方法完成的,但在添加新项目后我收到以下控制台错误。

错误

ForEach<Range<Int>, Int, HStack<TupleView<(Spacer, FriendView, Spacer)>>> count (4) != its initial count (3).
`ForEach(_:content:)` should only be used for *constant* data.
Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`!
Run Code Online (Sandbox Code Playgroud)

型号代码

ForEach<Range<Int>, Int, HStack<TupleView<(Spacer, FriendView, Spacer)>>> count (4) != its initial count (3).
`ForEach(_:content:)` should only be used for *constant* data.
Instead conform data to `Identifiable` or use …
Run Code Online (Sandbox Code Playgroud)

xcode ios swift swiftui observableobject

7
推荐指数
1
解决办法
1791
查看次数

如何将颜色选择器值保存到 SwiftUI 中的 UserDefaults 中?

我分配了一组颜色,希望将其保存到 UserDefaults 中。我有默认的灰色、绿色、橙色和红色,但我想允许颜色选择器更改绿色、橙色和红色。默认值在我的模拟器中有效并显示,但是当我尝试更改数组中的颜色时,出现错误“尝试插入非属性列表对象(\n“50% 灰色”、\n 绿色、\n ” kCGColorSpaceModelRGB 0.647194 0.881984 0.980039 1 “,\n 红色\n) 用于关键 SavedColors。” 我相信这是因为颜色选择器试图插入不同类型的颜色?看起来它可能正在尝试插入 CGColor 或 CGColorSpace ?

这是我的项目代码:

import SwiftUI
import Foundation
import Combine

class UserSettings: ObservableObject {
    @Published var colors: [Color] {
        didSet {
            UserDefaults.standard.set(colors, forKey: "SavedColors")
        }
    }
    init() {
        self.colors = UserDefaults.standard.object(forKey: "SavedColors") as? [Color] ?? [Color.gray.opacity(0.5), Color.green, Color.orange, Color.red]
    }
}

struct CustomizeView: View {
    @ObservedObject var savedColors = UserSettings()
    var body: some View {
        NavigationView {
            Form {
                if #available(iOS 14.0, *) …
Run Code Online (Sandbox Code Playgroud)

xcode swift userdefaults swiftui observableobject

7
推荐指数
1
解决办法
3078
查看次数

符合 ObservableObject 的 SwiftUI 类应该是 Singleton?

我被认为是 SwiftUI 的新手,我有下面的 ViewModel。但我不确定 MyViewModel 应该是单例的。这样的用法正确吗?符合 ObservableObject 的最佳实践/用法是什么?

class MyViewModel: ObservableObject {
    static let shared: MyViewModel = MyViewModel()
    
    @Published var result: String = ""
    
    private init() { }
    
    // some functions
}

struct ContentView: View {
    @ObservedObject private var vm = MyViewModel.shared
    
    var body: some View {
        Text(vm.result)
    }
}
Run Code Online (Sandbox Code Playgroud)

singleton swift swiftui observableobject

7
推荐指数
1
解决办法
4317
查看次数

SwiftUI - 从 NSObject 继承的 ObservableObject 在 iOS 13 中不会更新

我知道,这是“无法在 iOS XX 中工作”问题之一,但我完全陷入困境......

所以我有一个ObservableObject继承自 的类NSObject,因为我需要监听 的委托方法UISearchResultsUpdating

class SearchBarListener: NSObject, UISearchResultsUpdating, ObservableObject {
    
    @Published var searchText: String = ""
    let searchController: UISearchController = UISearchController(searchResultsController: nil)
    
    override init() {
        super.init()
        self.searchController.searchResultsUpdater = self
    }
    
    func updateSearchResults(for searchController: UISearchController) {
        
        /// Publish search bar text changes
        if let searchBarText = searchController.searchBar.text {
            print("text: \(searchBarText)")
            self.searchText = searchBarText
        }
    }
}

struct ContentView: View {
    @ObservedObject var searchBar = SearchBarListener()
    
    var body: some View {
        Text("Search text: …
Run Code Online (Sandbox Code Playgroud)

ios swift swiftui observableobject

7
推荐指数
1
解决办法
2105
查看次数

SwiftUI:当我执行函数时如何从观察到的对象中捕获变化的值

我在 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 swiftui combine observedobject observableobject

6
推荐指数
2
解决办法
7509
查看次数