Observation

RSS for tag

Make responsive apps that update the presentation when underlying data changes.

Posts under Observation tag

110 Posts

Post

Replies

Boosts

Views

Activity

@Observable observation outside of SwiftUI
I've just started tinkering with @Observable and have run into a question... What is the best practice for observing an Observable object outside of SwiftUI? For example: @Observable class CountingService { public var count: Int = 0 } @Observable class ObservableViewModel { public var service: CountingService init(service: CountingService) { self.service = service // how to bind to value changes on service? } // suggestion I've seen that doesn't smell right func checkCount() { _ = withObservationTracking { service.count } onChange: { DispatchQueue.main.async { print("count: \(service.count)") checkCount() } } } } Historically using ObservableObject I'd have used Combine to monitor changes to service. That doesn't seem possible with @Observable and I don't know that I've come across an accepted / elegant solution? Perhaps there isn't one? There's no particular reason that CountingService has to be @Observable -- it's just nice and clean. Any suggestions would be appreciated!
4
1
4.9k
May ’24
Trouble setting an optional @Observable object
i'm having trouble modifying an optional environment object. i'm using the .environment modifier to pass along an optional object to other views. to access it in other views, i have to get it through an @Environment property wrapper. but i can't modify it even if i redeclare it in the body as @Bindable. here's an example code: @main struct MyApp: App { @State private var mySession: MySession? var body: some Scene { HomeScreen() .environment(mySession) } } now for the HomeScreen: struct HomeScreen: View { @Environment(MySession.self) private var mySession: MySession? var body: some View { @Bindable var mySession = mySession Button { mySession = MySession() } label: { Text("Create Session") } } } an error shows up in the @Bindable declaration saying init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable. but MySession is declared as @Observable. in fact it works just fine if i don't make the environment optional, but i have to setup MySession in the root of the app, which goes against the app flow.
1
0
655
May ’24
@Observable does not conform with Equatable (and Hashable)
Since Xcode 15 beta 5, making a class with the @Observable macro no longer requires all properties to have an initialization value, as seen in the video. Just put an init that collects the properties and everything works correctly. @Observable final class Score: Identifiable { let id: Int var title: String var composer: String var year: Int var length: Int var cover: String var tracks: [String] init(id: Int, title: String, composer: String, year: Int, length: Int, cover: String, tracks: [String]) { self.id = id self.title = title self.composer = composer self.year = year self.length = length self.cover = cover self.tracks = tracks } } But there is a problem: the @Observable macro makes each property to integrate the @ObservationTracked macro that seems not to conform the types to Equatable, and in addition, to Hashable. Obviously, being a feature of each property, it is not useful to conform the class in a forced way with the static func == or with the hash(into:Hasher) function that conforms both protocols. That any class we want to be @Observable does not conform to Hashable, prevents any instance with the new pattern to be usable within a NavigationStack using the data driven navigation bindings and the navigationDestination(for:) modifier. I understand that no one has found a solution to this. If you have found it it would be great if you could share it but mainly I am making this post to invoke the mighty developers at Apple to fix this bug. Thank you very much. P.S. - I also posted a Feedback (FB12535713), but no one replies. At least that I see.
3
4
2.5k
Apr ’24
Observation and MainActor
Previously, it was recommended to use the @MainActor annotation for ObservableObject implementation. @MainActor final class MyModel: ObservableObject { let session: URLSession @Published var someText = "" init(session: URLSession) { self.session = session } } We could use this as either a @StateObject or @ObservedObject: struct MyView: View { @StateObject let model = MyModel(session: .shared) } By moving to Observation, I need to the @Observable macro, remove the @Published property wrappers and Switch @StateObject to @State: @MainActor @Observable final class MyModel { let session: URLSession var someText = "" init(session: URLSession) { self.session = session } } But switching from @StateObject to @State triggers me an error due to a call to main-actor isolated initialiser in a synchronous nonisolated context. This was not the case with @StateObject of @ObservedObject. To suppress the warning I could : mark the initializer as nonisolated but it is not actually what I want Mark the View with @MainActor but this sounds odd Both solutions does not sound nice to my eye. Did I miss something here?
9
3
7.3k
Apr ’24
Using .environment() for Observable Object
Hello everyone, I hope you are well. I have a question about .environment. I have an observable viewModel which has some functions and publishing value. I'm observing this viewModel in only 2 views but I'm using viewModel functions in every view. Should I use it (.environment). if I should use it, should I use this environment macro (@Environment(ViewModel.Self) var vm) for only functions in view? Thank you so much.
1
0
1k
Mar ’24
isPresented: on the basis of an observed object not being empty?
I am targeting iOS17 and using @Observable. I have an array of items, and I want to present a sheet when the array is greater than zero. My @Observable looks like this: @Observable class BStoreOO { var items: [Int] = [] var showBS: Bool { items.isEmpty } func updateItems(newItems: [Int]) { self.items = newItems } } When this array gets added to, from another view, I would like to present a sheet/popover. Inside my ContentView I have a @State `... that uses that @Observable struct ContentView: View { @State var bStore = BStoreOO() Further down in my View, how should I toggle this view on the basis of the observed array not being empty? I have tried a number of ways. Some error, some don't, but none present the sheet! For example: .popover(isPresented: bStore.showBS) { PopoverContent() } Gives the error "Cannot convert value of type 'Bool' to expected argument type 'Binding'" If I add a State like this: @State private var isShowingBS = false and then add this: .onChange(of: bStore.items) { self.isShowingBS = self.bStore.items.count > 0 } I don't get errors but nothing is presented. What is the correct way to bind the presentation of the sheet to whether the observed items array is empty or not?
6
0
844
Mar ’24
Is it possible to do something with @Observable class to make it constantly monitored and updatable?
Using SwiftUI, the timecode (seconds notation) has been referenced using ObservableObject as follows. In this case, the timecode values were reflected in Text in real time without any problem. struct ContentView: View { . . . var body: some View { NavigationStack { // Time Code Text Text(String(format:"%02d:%02d:%02d", sMinute, sSecond, sMsec)) .font(Font(UIFont.monospacedDigitSystemFont(ofSize: 30.0, weight: .regular))) class ViewModel: ObservableObject { // Time Code "%02d:%02d:%02d" @Published var sMinute = 0 @Published var sSecond = 0 @Published var sMsec = 0 When I changed it to @Observable class as follows, the timecode operation is stopped and the values are updated only when the operation is finished. @Observable class ViewModel { // Time Code "%02d:%02d:%02d" var sMinute = 0 var sSecond = 0 var sMsec = 0 Is it possible to do something with the @Observable class that would allow it to be constantly monitored and updated in real time? Or should we change it back? If we have a history of changing to @Observable in relation to other functions, and we have no choice but to revert back, is this where we need to make a change that would keep it functional separately?
3
0
911
Mar ’24
Sharing a Query in the Environment?
Using SwiftData I have one relatively short list of @Model class objects that are referenced in several views. I thought it would be handy to query once and share via the environment but my Table in other views does not update when data changes as it does when I repeat the Query in each view. Is this a bad idea or perhaps I implemented it improperly? @Observable class AllAccounts: ObservableObject { var accounts: [Account] = [] } struct ContentView: View { @Environment(\.modelContext) private var modelContext // an instance of the AllAccounts class, will save Query results to all.accounts @StateObject var all = AllAccounts() // one query for all accounts once in app, store in the environment` @Query private var allAccounts: [Account] .onAppear { all.accounts = allAccounts } .environment(all)
0
0
782
Mar ’24
Problems with Observable Macro and Observation: Observable is not member type of class 'Models.Observation'
Hey there i try to adept the Observable macro for my SwiftUI Project. I wanna get data from HealthKit and transform it to FHIR. Here i need one class for managing this process which will be shared through my project in order to access these data. The following Codesnippet raises an error: import Observation import HealthKit import FHIR @Observable class HealthKitManager{ let healthStore = HKHealthStore() init(){ } func requestAuthorization(){ let authTypes: Set = [HKQuantityType(.stepCount), HKQuantityType(.heartRate) ] guard HKHealthStore.isHealthDataAvailable() else { print("health data not available!") return } healthStore.requestAuthorization(toShare: nil, read: authTypes) { success, error in if success { print("OK Fetching") } else { print("\(String(describing: error))") } } } } So the FHIR module contains a Models module which define different models. In the FHIR world there is also a concept called observation... now the problems begin. open class Observation : Models.DomainResource { ... } When i try import Observation for the Observable macro and also import FHIR in order to create Observations, XCode rises an error: Observable' is not a member type of class 'Models.Observation' It's also said that Observation is declared in the FHIR.Models.Observation class which is true, but it seems that this raises the Problem with the @Observable macro. It's also said that Type 'Observation' has no member 'ObservationRegistrar' Which comes from the Observable Macro i think. When i don't import FHIR then everything works fine, but then my use case is broken because i need these standard in order to get my use case running. All in all i need big help and be thankfull for possible solutions!
1
0
876
Feb ’24
Previews crashing when using @Environment property wrapper
I am using the Observable macro and when I use @Environment property wrapper to instance my model the preview stop working. Sample code below my model Library import SwiftUI import Observation @Observable class Library { // ... } Now in my main app I created an instance of Library and add that instance to the environment @main struct BookReaderApp: App { @State private var library = Library() var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } Now if I want to retrieve the Library instance from any view using the @Environment property wrapper the preview stop working completely struct LibraryView: View { @Environment(Library.self) private var library var body: some View { List(library.books) { book in BookView(book: book) } } } #Preview { LibraryView() } Check the 2 screenshots below Any idea why this is happening? Is there any workaround? I am working with Xcode Version 15.2. Thanks in advance for any kind of help!
1
0
898
Jan ’24
How to address elements in an EnvironmentObject Array
I am new to programing apps, and I am trying to figure out how to use one item out of an array of items in a Text line. I am not getting any complaints from Xcode, but then the preview crashes giving me a huge error report that it keeps sending to Apple. I have cut out all the extra stuff from the app to get just the basics. What I want it to print on the screed is "Hello Bill How are you?" with Bill being from the observable array. The first picture below is about 2 seconds after I removed the // from in front of the line that reads Text("(friend2.friend2[1].name)"). The other two pictures are the main app page and the page where I setup the array. At the very bottom is a text file of the huge report it kept sending to Apple, until I turned of the option of sending to Apple. Would someone please explain what I am doing wrong. Well a side from probably everything. Error code.txt
1
0
797
Dec ’23
@Observable is being re-init every time view is modified
I am surprised at what I am seeing with the new @Observable framework in iOS 17. It seems that if the view containing the @State var, ie viewModel, is modified, then the init of that viewModel will also be called. This is not the behavior of the prior StateObject method of using a viewModel. As I understand the @State should not be reinitialized on redrawing on the View, is this the expected behavior? Example: struct ContentView: View { @State var offset = false var body: some View { VStack { InnerView() .offset(x: offset ? 200 : 0) Button("Offset") { offset.toggle() } } } } // iOS 17 Observable method: struct InnerView: View { @State var viewModel: ViewModel init() { self._viewModel = State(wrappedValue: ViewModel()) } var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } @Observable class ViewModel { init() { print("ViewModel Init") } } // StateObject method: struct InnerView: View { @StateObject var viewModel: ViewModel init() { self._viewModel = StateObject(wrappedValue: ViewModel()) } var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } class ViewModel: ObservableObject { init() { print("ViewModel Init") } }
2
1
1.3k
Dec ’23
Observable / State memory leak on view updates
I am working on a app that uses the new Observation framework and MVVM design pattern. I have a view composed of a list and a header that shows statistics about the displayed content by using an Observable ViewModel. When I add new contents, it is added to the list but the header seems to not take it into account even if its init method and body property are called. @Observable final class ViewModel { let contents: [String] init(contents: [String]) { self.contents = contents print("ViewModel init") } deinit { print("ViewModel deinit") } } struct ContentHeaderView: View { @State private var viewModel: ViewModel init(contents: [String]) { self._viewModel = State( initialValue: ViewModel(contents: contents) ) } var body: some View { Text("\(self.viewModel.contents.count)") } } struct ContentListView: View { @State private var contents = ["Content 1"] var body: some View { NavigationStack { VStack { ContentHeaderView(contents: self.contents) List(self.contents, id: \.self) { content in Text(content) } } .toolbar { ToolbarItem { Button("Add Content") { let newContent = "New Content \(self.contents.count + 1)" self.contents.append(newContent) } } } } } } In this example, when I tap the "Add Content" toolbar button, the header view that's supposed to show the number of content still display "1" even if the array now contains 2 elements. I added print statements to show that a new ViewModel is created every time the view is updated and the currently displayed view still uses the first created ViewModel which in fact contains a array with only one element. ContentHeaderView Init // on appear ContentHeaderView Init // First button tap // Every other tap ContentHeaderView Init ContentHeaderView Deinit I've read the threads 736239 and 736110 that discusses about similar issues when presenting sheets. I have similar code without issues since it's been fixed in iOS 17.2 beta 1 but it seems to still happen on view updates. Can you please confirm that this is an issue with the Observable framework and State properties or is there something I'm doing wrong ? Thanks
0
0
824
Dec ’23
Can't use @observable
after i import swiftui, there's no @observable?? it shows unknown attribute... and i cant import observation or swiftdata import Foundation import SwiftUI @Observable class BusinessModel{ var businesses = [Business]() var selectedBusiness: Business? var input: String = "" var service = dataservice() }
2
0
1.2k
Dec ’23
No Observable Object of type...found
I am learning SwiftUI. Error: SwiftUI/Environment+Objects.swift:32: Fatal error: No Observable object of type ViewModel found. A View.environmentObject(_:) for ViewModel may be missing as an ancestor of this view. I do not get the point why this happens. The error is shown in the line : "renderer.render {... import SwiftData import SwiftUI @Observable class ViewModel { var groupNumber: String = "Gruppe" var sumOfHours: Int = 0 var personsToPrint: [Person]? = nil @MainActor func pdfReport(person: [Person]) { if personsToPrint != nil { for person in personsToPrint! { let renderer = ImageRenderer(content: PersonDetailView(person: person)) let url = URL.documentsDirectory.appending(path: "\(person.lastname) \(person.firstname).pdf") print(person.lastname, person.firstname) renderer.render { size, context in var box = CGRect(x: 0, y: 0, width: size.width, height: size.height) guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else { return } pdf.beginPDFPage(nil) context(pdf) pdf.endPDFPage() pdf.closePDF() let data = try! Data(contentsOf: url) //pdf muss erst in Daten umgewandelt werden. do { try data.write(to: url) print("Daten wurden hier gespeichert: \(url)") } catch { print("PDF could not be saved!") } } } } } }
1
0
1.1k
Dec ’23
@Environment for new @Observable macro not creating bindings?
Hi guys, I am trying to use the new @Observable macro. According to the documentation, this new macro will automatically generate observable properties, but I am having issues using my properties when Bindings are necessary. Previously I had a setup like this: class Example: ObservableObject { @Published public var myArray = [CustomType]() } I initialised one instance of the Example-class in @main @StateObject private var exampleClass = Example() And added as an .environmentObject onto the root view ContentView() .environmentObject(exampleClass) In child views I was able to access the @Published property as a binding via @EnvironmentObject private var example: Example $example.myArray What I am trying now This is the setup that I am trying with now: @Observable class Example { public var myArray = [CustomType]() } State instead of StateObject in @main @State private var exampleClass = Example() .environment instead of .environmentObject ContentView() .environmentObject(exampleClass) @Environment instead of @EnvironmentObject @Environment(Example.self) private var example This new setup is not letting me access $example.myArray. Is this intended? Could someone explain why?
2
2
1.3k
Dec ’23
AVPlayer observePlayingState with @ObservationTracked possible?
I am following this Apple Article on how to setup an AVPlayer. The only difference is I am using @Observable instead of an ObservableObject with @Published vars. Using @Observable results in the following error: Cannot find '$isPlaying' in scope If I remove the "$" symbol I get a bit more insight: Cannot convert value of type 'Bool' to expected argument type 'Published<Bool>.Publisher' If I change by class to an OO, it works fine, although, is there anyway to get this to work with @Observable?
1
0
777
Nov ’23
AVFoundation player.publisher().assign() for @Observable/@ObservationTracked?
Following this Apple Article, I copied their code over for observePlayingState(). The only difference I am using @Observable instead of ObservableObject and @Published for var isPlaying. We get a bit more insight after removing the $ symbol, leading to a more telling error of: Cannot convert value of type 'Bool' to expected argument type 'Published.Publisher' Is there anyway to get this working with @Observable?
2
0
1.1k
Nov ’23
@Observable/@State memory leak
Not sure if this code is supposed to leak memory or am I missing something? import SwiftUI import Observation @Observable class SheetViewModel { let color: Color = Color.red init() { print("init") } deinit { print("deinit") } } struct SheetView: View { @State var viewModel = SheetViewModel() var body: some View { Color(viewModel.color) } } @main struct ObservableMemoryLeakApp: App { @State var presented: Bool = false var body: some Scene { WindowGroup { Button("Show") { presented = true } .sheet(isPresented: $presented) { SheetView() } } } } Every time the sheet is presented/dismissed, a new SheetViewModel is created (init is printed) but it never released (deinit not printed). Also, all previously created SheetViewModel instances are visible in Memory Graph and have "Leaked allocation" badge. Reverting to ObservableObject/@StateObject fixes the issue, deinit is called every time the sheet is dismissed: -import Observation -@Observable class SheetViewModel { +class SheetViewModel: ObservableObject { - @State var viewModel = SheetViewModel() + @StateObject var viewModel = SheetViewModel() Does this mean there's a bug in Observation framework? Reported as FB13015569.
7
10
4.4k
Nov ’23
.visualEffect with @Observable works only once
In my test app I have two squares (red and green) that change their size when I click a toggle button. I use two different approaches to change the scale. The red square is scaled using the .visualEffect modifier and the green square is scaled using the .scaleEffect modifier. When I click the button the first time, both squares change size. But when I click again and again, only the green square changes its size. The red square stays the same after the first change. Self._printChanges() show that both views get changes each time. What am I doing wrong? Or is this a bug? import SwiftUI import Observation struct ContentView: View { @State private var model: Model = Model() var body: some View { VStack { HStack { RedSquareView() GreenSquareView() } .environment(model) Button { model.scaled.toggle() } label: { Text("Toggle scale") } } .padding() } } struct RedSquareView: View { @Environment(Model.self) var model var body: some View { let _ = Self._printChanges() Rectangle() .fill(Color.red) .frame(width: 100, height: 100) .visualEffect { content, geometryProxy in content.scaleEffect(model.scaled ? 0.5 : 1.0, anchor: .center) } .animation(.bouncy, value: model.scaled) } } struct GreenSquareView: View { @Environment(Model.self) var model var body: some View { let _ = Self._printChanges() Rectangle() .fill(Color.green) .frame(width: 100, height: 100) .scaleEffect(model.scaled ? 0.5 : 1.0, anchor: .center) .animation(.bouncy, value: model.scaled) } } @Observable final class Model: Sendable { var scaled: Bool = false } #Preview { ContentView() }
0
0
566
Nov ’23
@Observable observation outside of SwiftUI
I've just started tinkering with @Observable and have run into a question... What is the best practice for observing an Observable object outside of SwiftUI? For example: @Observable class CountingService { public var count: Int = 0 } @Observable class ObservableViewModel { public var service: CountingService init(service: CountingService) { self.service = service // how to bind to value changes on service? } // suggestion I've seen that doesn't smell right func checkCount() { _ = withObservationTracking { service.count } onChange: { DispatchQueue.main.async { print("count: \(service.count)") checkCount() } } } } Historically using ObservableObject I'd have used Combine to monitor changes to service. That doesn't seem possible with @Observable and I don't know that I've come across an accepted / elegant solution? Perhaps there isn't one? There's no particular reason that CountingService has to be @Observable -- it's just nice and clean. Any suggestions would be appreciated!
Replies
4
Boosts
1
Views
4.9k
Activity
May ’24
Trouble setting an optional @Observable object
i'm having trouble modifying an optional environment object. i'm using the .environment modifier to pass along an optional object to other views. to access it in other views, i have to get it through an @Environment property wrapper. but i can't modify it even if i redeclare it in the body as @Bindable. here's an example code: @main struct MyApp: App { @State private var mySession: MySession? var body: some Scene { HomeScreen() .environment(mySession) } } now for the HomeScreen: struct HomeScreen: View { @Environment(MySession.self) private var mySession: MySession? var body: some View { @Bindable var mySession = mySession Button { mySession = MySession() } label: { Text("Create Session") } } } an error shows up in the @Bindable declaration saying init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable. but MySession is declared as @Observable. in fact it works just fine if i don't make the environment optional, but i have to setup MySession in the root of the app, which goes against the app flow.
Replies
1
Boosts
0
Views
655
Activity
May ’24
@Observable does not conform with Equatable (and Hashable)
Since Xcode 15 beta 5, making a class with the @Observable macro no longer requires all properties to have an initialization value, as seen in the video. Just put an init that collects the properties and everything works correctly. @Observable final class Score: Identifiable { let id: Int var title: String var composer: String var year: Int var length: Int var cover: String var tracks: [String] init(id: Int, title: String, composer: String, year: Int, length: Int, cover: String, tracks: [String]) { self.id = id self.title = title self.composer = composer self.year = year self.length = length self.cover = cover self.tracks = tracks } } But there is a problem: the @Observable macro makes each property to integrate the @ObservationTracked macro that seems not to conform the types to Equatable, and in addition, to Hashable. Obviously, being a feature of each property, it is not useful to conform the class in a forced way with the static func == or with the hash(into:Hasher) function that conforms both protocols. That any class we want to be @Observable does not conform to Hashable, prevents any instance with the new pattern to be usable within a NavigationStack using the data driven navigation bindings and the navigationDestination(for:) modifier. I understand that no one has found a solution to this. If you have found it it would be great if you could share it but mainly I am making this post to invoke the mighty developers at Apple to fix this bug. Thank you very much. P.S. - I also posted a Feedback (FB12535713), but no one replies. At least that I see.
Replies
3
Boosts
4
Views
2.5k
Activity
Apr ’24
Observation and MainActor
Previously, it was recommended to use the @MainActor annotation for ObservableObject implementation. @MainActor final class MyModel: ObservableObject { let session: URLSession @Published var someText = "" init(session: URLSession) { self.session = session } } We could use this as either a @StateObject or @ObservedObject: struct MyView: View { @StateObject let model = MyModel(session: .shared) } By moving to Observation, I need to the @Observable macro, remove the @Published property wrappers and Switch @StateObject to @State: @MainActor @Observable final class MyModel { let session: URLSession var someText = "" init(session: URLSession) { self.session = session } } But switching from @StateObject to @State triggers me an error due to a call to main-actor isolated initialiser in a synchronous nonisolated context. This was not the case with @StateObject of @ObservedObject. To suppress the warning I could : mark the initializer as nonisolated but it is not actually what I want Mark the View with @MainActor but this sounds odd Both solutions does not sound nice to my eye. Did I miss something here?
Replies
9
Boosts
3
Views
7.3k
Activity
Apr ’24
Using .environment() for Observable Object
Hello everyone, I hope you are well. I have a question about .environment. I have an observable viewModel which has some functions and publishing value. I'm observing this viewModel in only 2 views but I'm using viewModel functions in every view. Should I use it (.environment). if I should use it, should I use this environment macro (@Environment(ViewModel.Self) var vm) for only functions in view? Thank you so much.
Replies
1
Boosts
0
Views
1k
Activity
Mar ’24
isPresented: on the basis of an observed object not being empty?
I am targeting iOS17 and using @Observable. I have an array of items, and I want to present a sheet when the array is greater than zero. My @Observable looks like this: @Observable class BStoreOO { var items: [Int] = [] var showBS: Bool { items.isEmpty } func updateItems(newItems: [Int]) { self.items = newItems } } When this array gets added to, from another view, I would like to present a sheet/popover. Inside my ContentView I have a @State `... that uses that @Observable struct ContentView: View { @State var bStore = BStoreOO() Further down in my View, how should I toggle this view on the basis of the observed array not being empty? I have tried a number of ways. Some error, some don't, but none present the sheet! For example: .popover(isPresented: bStore.showBS) { PopoverContent() } Gives the error "Cannot convert value of type 'Bool' to expected argument type 'Binding'" If I add a State like this: @State private var isShowingBS = false and then add this: .onChange(of: bStore.items) { self.isShowingBS = self.bStore.items.count &gt; 0 } I don't get errors but nothing is presented. What is the correct way to bind the presentation of the sheet to whether the observed items array is empty or not?
Replies
6
Boosts
0
Views
844
Activity
Mar ’24
Is it possible to do something with @Observable class to make it constantly monitored and updatable?
Using SwiftUI, the timecode (seconds notation) has been referenced using ObservableObject as follows. In this case, the timecode values were reflected in Text in real time without any problem. struct ContentView: View { . . . var body: some View { NavigationStack { // Time Code Text Text(String(format:"%02d:%02d:%02d", sMinute, sSecond, sMsec)) .font(Font(UIFont.monospacedDigitSystemFont(ofSize: 30.0, weight: .regular))) class ViewModel: ObservableObject { // Time Code "%02d:%02d:%02d" @Published var sMinute = 0 @Published var sSecond = 0 @Published var sMsec = 0 When I changed it to @Observable class as follows, the timecode operation is stopped and the values are updated only when the operation is finished. @Observable class ViewModel { // Time Code "%02d:%02d:%02d" var sMinute = 0 var sSecond = 0 var sMsec = 0 Is it possible to do something with the @Observable class that would allow it to be constantly monitored and updated in real time? Or should we change it back? If we have a history of changing to @Observable in relation to other functions, and we have no choice but to revert back, is this where we need to make a change that would keep it functional separately?
Replies
3
Boosts
0
Views
911
Activity
Mar ’24
Sharing a Query in the Environment?
Using SwiftData I have one relatively short list of @Model class objects that are referenced in several views. I thought it would be handy to query once and share via the environment but my Table in other views does not update when data changes as it does when I repeat the Query in each view. Is this a bad idea or perhaps I implemented it improperly? @Observable class AllAccounts: ObservableObject { var accounts: [Account] = [] } struct ContentView: View { @Environment(\.modelContext) private var modelContext // an instance of the AllAccounts class, will save Query results to all.accounts @StateObject var all = AllAccounts() // one query for all accounts once in app, store in the environment` @Query private var allAccounts: [Account] .onAppear { all.accounts = allAccounts } .environment(all)
Replies
0
Boosts
0
Views
782
Activity
Mar ’24
Problems with Observable Macro and Observation: Observable is not member type of class 'Models.Observation'
Hey there i try to adept the Observable macro for my SwiftUI Project. I wanna get data from HealthKit and transform it to FHIR. Here i need one class for managing this process which will be shared through my project in order to access these data. The following Codesnippet raises an error: import Observation import HealthKit import FHIR @Observable class HealthKitManager{ let healthStore = HKHealthStore() init(){ } func requestAuthorization(){ let authTypes: Set = [HKQuantityType(.stepCount), HKQuantityType(.heartRate) ] guard HKHealthStore.isHealthDataAvailable() else { print("health data not available!") return } healthStore.requestAuthorization(toShare: nil, read: authTypes) { success, error in if success { print("OK Fetching") } else { print("\(String(describing: error))") } } } } So the FHIR module contains a Models module which define different models. In the FHIR world there is also a concept called observation... now the problems begin. open class Observation : Models.DomainResource { ... } When i try import Observation for the Observable macro and also import FHIR in order to create Observations, XCode rises an error: Observable' is not a member type of class 'Models.Observation' It's also said that Observation is declared in the FHIR.Models.Observation class which is true, but it seems that this raises the Problem with the @Observable macro. It's also said that Type 'Observation' has no member 'ObservationRegistrar' Which comes from the Observable Macro i think. When i don't import FHIR then everything works fine, but then my use case is broken because i need these standard in order to get my use case running. All in all i need big help and be thankfull for possible solutions!
Replies
1
Boosts
0
Views
876
Activity
Feb ’24
Previews crashing when using @Environment property wrapper
I am using the Observable macro and when I use @Environment property wrapper to instance my model the preview stop working. Sample code below my model Library import SwiftUI import Observation @Observable class Library { // ... } Now in my main app I created an instance of Library and add that instance to the environment @main struct BookReaderApp: App { @State private var library = Library() var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } Now if I want to retrieve the Library instance from any view using the @Environment property wrapper the preview stop working completely struct LibraryView: View { @Environment(Library.self) private var library var body: some View { List(library.books) { book in BookView(book: book) } } } #Preview { LibraryView() } Check the 2 screenshots below Any idea why this is happening? Is there any workaround? I am working with Xcode Version 15.2. Thanks in advance for any kind of help!
Replies
1
Boosts
0
Views
898
Activity
Jan ’24
How to address elements in an EnvironmentObject Array
I am new to programing apps, and I am trying to figure out how to use one item out of an array of items in a Text line. I am not getting any complaints from Xcode, but then the preview crashes giving me a huge error report that it keeps sending to Apple. I have cut out all the extra stuff from the app to get just the basics. What I want it to print on the screed is "Hello Bill How are you?" with Bill being from the observable array. The first picture below is about 2 seconds after I removed the // from in front of the line that reads Text("(friend2.friend2[1].name)"). The other two pictures are the main app page and the page where I setup the array. At the very bottom is a text file of the huge report it kept sending to Apple, until I turned of the option of sending to Apple. Would someone please explain what I am doing wrong. Well a side from probably everything. Error code.txt
Replies
1
Boosts
0
Views
797
Activity
Dec ’23
@Observable is being re-init every time view is modified
I am surprised at what I am seeing with the new @Observable framework in iOS 17. It seems that if the view containing the @State var, ie viewModel, is modified, then the init of that viewModel will also be called. This is not the behavior of the prior StateObject method of using a viewModel. As I understand the @State should not be reinitialized on redrawing on the View, is this the expected behavior? Example: struct ContentView: View { @State var offset = false var body: some View { VStack { InnerView() .offset(x: offset ? 200 : 0) Button("Offset") { offset.toggle() } } } } // iOS 17 Observable method: struct InnerView: View { @State var viewModel: ViewModel init() { self._viewModel = State(wrappedValue: ViewModel()) } var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } @Observable class ViewModel { init() { print("ViewModel Init") } } // StateObject method: struct InnerView: View { @StateObject var viewModel: ViewModel init() { self._viewModel = StateObject(wrappedValue: ViewModel()) } var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } class ViewModel: ObservableObject { init() { print("ViewModel Init") } }
Replies
2
Boosts
1
Views
1.3k
Activity
Dec ’23
Observable / State memory leak on view updates
I am working on a app that uses the new Observation framework and MVVM design pattern. I have a view composed of a list and a header that shows statistics about the displayed content by using an Observable ViewModel. When I add new contents, it is added to the list but the header seems to not take it into account even if its init method and body property are called. @Observable final class ViewModel { let contents: [String] init(contents: [String]) { self.contents = contents print("ViewModel init") } deinit { print("ViewModel deinit") } } struct ContentHeaderView: View { @State private var viewModel: ViewModel init(contents: [String]) { self._viewModel = State( initialValue: ViewModel(contents: contents) ) } var body: some View { Text("\(self.viewModel.contents.count)") } } struct ContentListView: View { @State private var contents = ["Content 1"] var body: some View { NavigationStack { VStack { ContentHeaderView(contents: self.contents) List(self.contents, id: \.self) { content in Text(content) } } .toolbar { ToolbarItem { Button("Add Content") { let newContent = "New Content \(self.contents.count + 1)" self.contents.append(newContent) } } } } } } In this example, when I tap the "Add Content" toolbar button, the header view that's supposed to show the number of content still display "1" even if the array now contains 2 elements. I added print statements to show that a new ViewModel is created every time the view is updated and the currently displayed view still uses the first created ViewModel which in fact contains a array with only one element. ContentHeaderView Init // on appear ContentHeaderView Init // First button tap // Every other tap ContentHeaderView Init ContentHeaderView Deinit I've read the threads 736239 and 736110 that discusses about similar issues when presenting sheets. I have similar code without issues since it's been fixed in iOS 17.2 beta 1 but it seems to still happen on view updates. Can you please confirm that this is an issue with the Observable framework and State properties or is there something I'm doing wrong ? Thanks
Replies
0
Boosts
0
Views
824
Activity
Dec ’23
Can't use @observable
after i import swiftui, there's no @observable?? it shows unknown attribute... and i cant import observation or swiftdata import Foundation import SwiftUI @Observable class BusinessModel{ var businesses = [Business]() var selectedBusiness: Business? var input: String = "" var service = dataservice() }
Replies
2
Boosts
0
Views
1.2k
Activity
Dec ’23
No Observable Object of type...found
I am learning SwiftUI. Error: SwiftUI/Environment+Objects.swift:32: Fatal error: No Observable object of type ViewModel found. A View.environmentObject(_:) for ViewModel may be missing as an ancestor of this view. I do not get the point why this happens. The error is shown in the line : "renderer.render {... import SwiftData import SwiftUI @Observable class ViewModel { var groupNumber: String = "Gruppe" var sumOfHours: Int = 0 var personsToPrint: [Person]? = nil @MainActor func pdfReport(person: [Person]) { if personsToPrint != nil { for person in personsToPrint! { let renderer = ImageRenderer(content: PersonDetailView(person: person)) let url = URL.documentsDirectory.appending(path: "\(person.lastname) \(person.firstname).pdf") print(person.lastname, person.firstname) renderer.render { size, context in var box = CGRect(x: 0, y: 0, width: size.width, height: size.height) guard let pdf = CGContext(url as CFURL, mediaBox: &box, nil) else { return } pdf.beginPDFPage(nil) context(pdf) pdf.endPDFPage() pdf.closePDF() let data = try! Data(contentsOf: url) //pdf muss erst in Daten umgewandelt werden. do { try data.write(to: url) print("Daten wurden hier gespeichert: \(url)") } catch { print("PDF could not be saved!") } } } } } }
Replies
1
Boosts
0
Views
1.1k
Activity
Dec ’23
@Environment for new @Observable macro not creating bindings?
Hi guys, I am trying to use the new @Observable macro. According to the documentation, this new macro will automatically generate observable properties, but I am having issues using my properties when Bindings are necessary. Previously I had a setup like this: class Example: ObservableObject { @Published public var myArray = [CustomType]() } I initialised one instance of the Example-class in @main @StateObject private var exampleClass = Example() And added as an .environmentObject onto the root view ContentView() .environmentObject(exampleClass) In child views I was able to access the @Published property as a binding via @EnvironmentObject private var example: Example $example.myArray What I am trying now This is the setup that I am trying with now: @Observable class Example { public var myArray = [CustomType]() } State instead of StateObject in @main @State private var exampleClass = Example() .environment instead of .environmentObject ContentView() .environmentObject(exampleClass) @Environment instead of @EnvironmentObject @Environment(Example.self) private var example This new setup is not letting me access $example.myArray. Is this intended? Could someone explain why?
Replies
2
Boosts
2
Views
1.3k
Activity
Dec ’23
AVPlayer observePlayingState with @ObservationTracked possible?
I am following this Apple Article on how to setup an AVPlayer. The only difference is I am using @Observable instead of an ObservableObject with @Published vars. Using @Observable results in the following error: Cannot find '$isPlaying' in scope If I remove the "$" symbol I get a bit more insight: Cannot convert value of type 'Bool' to expected argument type 'Published<Bool>.Publisher' If I change by class to an OO, it works fine, although, is there anyway to get this to work with @Observable?
Replies
1
Boosts
0
Views
777
Activity
Nov ’23
AVFoundation player.publisher().assign() for @Observable/@ObservationTracked?
Following this Apple Article, I copied their code over for observePlayingState(). The only difference I am using @Observable instead of ObservableObject and @Published for var isPlaying. We get a bit more insight after removing the $ symbol, leading to a more telling error of: Cannot convert value of type 'Bool' to expected argument type 'Published.Publisher' Is there anyway to get this working with @Observable?
Replies
2
Boosts
0
Views
1.1k
Activity
Nov ’23
@Observable/@State memory leak
Not sure if this code is supposed to leak memory or am I missing something? import SwiftUI import Observation @Observable class SheetViewModel { let color: Color = Color.red init() { print("init") } deinit { print("deinit") } } struct SheetView: View { @State var viewModel = SheetViewModel() var body: some View { Color(viewModel.color) } } @main struct ObservableMemoryLeakApp: App { @State var presented: Bool = false var body: some Scene { WindowGroup { Button("Show") { presented = true } .sheet(isPresented: $presented) { SheetView() } } } } Every time the sheet is presented/dismissed, a new SheetViewModel is created (init is printed) but it never released (deinit not printed). Also, all previously created SheetViewModel instances are visible in Memory Graph and have "Leaked allocation" badge. Reverting to ObservableObject/@StateObject fixes the issue, deinit is called every time the sheet is dismissed: -import Observation -@Observable class SheetViewModel { +class SheetViewModel: ObservableObject { - @State var viewModel = SheetViewModel() + @StateObject var viewModel = SheetViewModel() Does this mean there's a bug in Observation framework? Reported as FB13015569.
Replies
7
Boosts
10
Views
4.4k
Activity
Nov ’23
.visualEffect with @Observable works only once
In my test app I have two squares (red and green) that change their size when I click a toggle button. I use two different approaches to change the scale. The red square is scaled using the .visualEffect modifier and the green square is scaled using the .scaleEffect modifier. When I click the button the first time, both squares change size. But when I click again and again, only the green square changes its size. The red square stays the same after the first change. Self._printChanges() show that both views get changes each time. What am I doing wrong? Or is this a bug? import SwiftUI import Observation struct ContentView: View { @State private var model: Model = Model() var body: some View { VStack { HStack { RedSquareView() GreenSquareView() } .environment(model) Button { model.scaled.toggle() } label: { Text("Toggle scale") } } .padding() } } struct RedSquareView: View { @Environment(Model.self) var model var body: some View { let _ = Self._printChanges() Rectangle() .fill(Color.red) .frame(width: 100, height: 100) .visualEffect { content, geometryProxy in content.scaleEffect(model.scaled ? 0.5 : 1.0, anchor: .center) } .animation(.bouncy, value: model.scaled) } } struct GreenSquareView: View { @Environment(Model.self) var model var body: some View { let _ = Self._printChanges() Rectangle() .fill(Color.green) .frame(width: 100, height: 100) .scaleEffect(model.scaled ? 0.5 : 1.0, anchor: .center) .animation(.bouncy, value: model.scaled) } } @Observable final class Model: Sendable { var scaled: Bool = false } #Preview { ContentView() }
Replies
0
Boosts
0
Views
566
Activity
Nov ’23