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

Bindable is never deallocated
I've encountered a problem which I don't know if is related to swiftui, the observation framework, or both If I run the following code I have two tabs, with the second tab that use a "lazy model" which is deallocated each time disappears (this is necessary for my use case) If I switch to the second tab, all works right. If I return to the first tab, the onDisappear on the foo view should force the "Bar" variable to nil , because the FooView may be still allocated (it is a tab bar) but that resource should be released If that bar variable is set to nil, the MyBar should be replaced by the ProgressView in the "background" I expect regarding that the Bar that: the instance is nil on Foo no other view should be shown with that instance (MyBar is now disappeared) Because no ref, the Bar observable object should be now deallocated In reality the Bar object is still in my memory graph Any suggestions? is it a bug? @Observable class Bar { var hello: String = "" } struct Foo: View { @State var bar: Bar? @ViewBuilder private var content: some View { if let bar { MyBar(bar: bar) } else { ProgressView() } } var body: some View { content .onAppear { bar = Bar() } .onDisappear { self.bar = nil } } } struct MyBar: View { @Bindable var bar: Bar var body: some View { Text("MyBar") } } struct ContentView: View { @State var tag: Int = 0 var body: some View { TabView(selection: $tag) { Text("First") .tag(0) .tabItem { Text("First") } Foo() .tag(1) .tabItem { Text("Foo") } } } }
1
0
879
Nov ’23
SwiftUI: Grandparent View Not Updating on Model Change in SwiftData
I'm working on a SwiftUI app using SwiftData for state management. I've encountered an issue with view updates when mutating a model. Here's a minimal example to illustrate the problem: import SwiftUI import SwiftData // MARK: - Models @Model class A { @Relationship var bs: [B] = [B]() init(bs: [B]) { self.bs = bs } } @Model class B { @Relationship var cs: [C] = [C]() init(cs: [C]) { self.cs = cs } } @Model class C { var done: Bool init(done: Bool) { self.done = done } } // MARK: - Views struct CView: View { var c: C var body: some View { @Bindable var c = c HStack { Toggle(isOn: $c.done, label: { Text("Done") }) } } } struct BView: View { var b: B var body: some View { List(b.cs) { c in CView(c: c) } } } struct AView: View { var a: A var body: some View { List(a.bs) { b in NavigationLink { BView(b: b) } label: { Text("B \(b.cs.allSatisfy({ $0.done }).description)") } } } } struct ContentView: View { @Query private var aList: [A] var body: some View { NavigationStack { List(aList) { a in NavigationLink { AView(a: a) } label: { Text("A \(a.bs.allSatisfy({ $0.cs.allSatisfy({ $0.done }) }).description)") } } } } } @main struct Minimal: App { var body: some Scene { WindowGroup { ContentView() } } } #Preview { let config = ModelConfiguration(isStoredInMemoryOnly: true) let container = try! ModelContainer(for: A.self, configurations: config) var c = C(done: false) container.mainContext.insert(c) var b = B(cs: [c]) container.mainContext.insert(b) var a = A(bs: [b]) container.mainContext.insert(a) return ContentView() .modelContainer(container) } In this setup, I have a CView where I toggle the state of a model C. After toggling C and navigating back, the grandparent view AView does not reflect the updated state (it still shows false instead of true). However, if I navigate back to the root ContentView and then go to AView, the status is updated correctly. Why doesn't AView update immediately after mutating C in CView, but updates correctly when navigating back to the root ContentView? I expected the grandparent view to reflect the changes immediately as per SwiftData's observation mechanism.
1
1
797
Nov ’23
[SwiftData] Bugs with `autosaveEnabled` and `undoManager` + Observation
Hello, my goal is it to implement an Edit Sheet of a Model with Discard changes in SwiftData. Xcode Version 15.0 beta 6 (15A5219j) Approaches In the following modelContext refers to the context fetched from the environment by the View. Also code for showing the sheet (eg. toggling isPresented) is omitted. // App ContentView() .modelContainer(for: Model.self, isAutosaveEnabled: true, isUndoEnabled: true) // In Content View @Query var models: [Model] //... ForEach(models) { model in ModelView(model: model) //eg. longpresgesture that calls openEditSheet .sheet(..., content: { EditModelView(model: model) } } Disabling autosave + rollback // In ContentView func openEditSheet() { modelContext.autosaveEnabled = false } // In EditModelView func discardEditSheet() { modelContext.rollback() modelContext.autosaveEnabled = true } func saveEditSheet() { try? modelContext.save() // probably not needed if autosave gets enabled anyway modelContext.autosaveEnabled = true } However this approach does not work, as SwiftData continues to save anyway and therefore there is nothing to rollback. modelContext in Memory // In ContentView let context = ModelContext(modelContext.container) context.autosaveEnabled = false context.container.configuration.removeAll() context.container.configuration.insert(ModelConfiguration(..., inMemory: true) //... EditModelView() .modelContext(context) // Also tried: .enviroment(\.modelContext, context) // In EditModelView func discardEditSheet() { modelContext.rollback() // probably not needed as the container is never saved } func saveEditSheet() { try? modelContext.save() // move to persistent storage from memory } The idea was to use something like parent in CoreData. However as this is (currently) not supported. Also tried this by modifying the modelContext directly (instead of creating a new context) and its container directly or before creating the context. The child can not be a ModelContainer as you can not pass a context to it or set its mainContext (get-only). However this approach does not work, as the container does not seem to stay in memory. Maybe related to previous. BackingData EditModelView(model: Model(backingData: model.persistentBackingData) not sure about this one, played around a little with it but not sure what it means / should mean and how I would expect it to work. I have never been great at cooking :). UndoManager (preferred) // In ContentView func openEditSheet() { modelContext.undoManager?.beginUndoGrouping() } // In EditModelView func discardEditSheet() { modelContext.undoManager?.endUndoGrouping() modelContext.undoManager?.undoNestedGroup() // Also tried adding: try? modelContext.save() } func saveEditSheet() { modelContext.undoManager?.endUndoGrouping() } This approach does works kinda weird: The ModelView of the updated model in ContentView's ForEach is not updated regarding the undo action. However when I re-open the EditTaskView of the updated model it has the expected state, even though the model to edit is passed by the ContentView (which does not have the correct state?). After relaunching the app or when modifying the model again (this time not undoing) the previous sate changes are recognised Therefore this looks like it does what I want, with the ContentView having the correct state, but not displaying it. Only reason I can think of is the Model: Observable not getting triggered and therefore no View update. Conclusion After playing around with the above approaches and combining them in every possible way, i think that: disabling autosave at runtime is currently not working and this is a bug (otherwise autosaveEnabled should be get-only). UndoManager does not trigger a View update of a Model/Observable and this is a bug Would be happy to hear other opinions on this. Am I missing something here? Am I ******? Question However as my conclusion does not fix my problem I am wondering: Are my approaches (theoretically) correct? How do I fix / workaround the UndoManager issue? If I identified it correctly, how can I manually notify the view that a Observable model has changed?
3
3
2.2k
Nov ’23
When I create an object, the view is updated, but when I update data inside that object, the view is not updated
class PostManager: ObservableObject { static let shared = PostManager() private init() {} @Published var containers: [PostContainer] = [] // Other code } class PostContainer: ObservableObject { var id: UUID = UUID() var timestamp: Date var subreddit: String var posts: [Post] var type: ContainerType var active: Bool // Init } @Model final class Post: Decodable, ObservableObject { // Other code } In my main view, a network request is made and a PostContainer is created if it doesn't exist. This code works fine, and the view is updated correctly. let container = PostContainer(timestamp: Date(), subreddit: subreddit, posts: posts, type: .search, active: true) self.containers.append(container) If the user wants to see more, they press a button and another request is made. This time, the new data will be added to the PostContainer instead of creating a new one. if let container = self.containers.first(where: {$0.subreddit == subreddit}) { // Update previous container container.timestamp = Date() print(container.posts.count) // Map IDs from container and then remove duplicates let existingIDs = Set(container.posts.map { $0.id }) let filtered = posts.filter { !existingIDs.contains($0.id) } // Append new post container.posts.append(contentsOf: filtered) container.active = true } This code is working fine as well, except for the view is not updating. In the view, PostManager is an @EnvironmentObject. I also have a computed variable to get the post and sort them. I added a print statement to that variable and saw that it wasn't being printed even though more data was being added to the PostContainer. At one point, I created an ID for the List that displays the data and had the code inside PostManager update that ID when it was finished. This of course worked, but it's not ideal. How can I get the view to update when post are appended inside of PostContainer?
1
0
605
Nov ’23
iOS 17b6: Simultaneous accesses to ..., but modification requires exclusive access crash using Observation and SwiftUI
Since iOS/iPadOS beta 6, I get a crash just by simply selecting an item in the sidebar of a navigation view. The selected item is part of an app mode, with conforms to the Observation protocol: import SwiftUI import Observation @main struct MREAApp: App { @State private var appModel = AppModel.shared var body: some Scene { WindowGroup { ContentView() .environment(appModel) } } } @Observable class AppModel { static var shared = AppModel() var selectedFolder: Folder? = nil } struct Folder: Hashable, Identifiable { let id = UUID() let name: String } struct ContentView: View { @Environment(AppModel.self) private var appModel var folders = [Folder(name: "Recents"), Folder(name: "Deleted"), Folder(name: "Custom")] var body: some View { NavigationSplitView { SidebarView(appModel: appModel, folders: folders) } detail: { if let folder = appModel.selectedFolder { Text(folder.name) } else { Text("No selection") } } } } struct SidebarView: View { @Bindable var appModel: AppModel var folders: [Folder] var body: some View { List(selection: $appModel.selectedFolder) { ForEach(folders, id: \.self) { folder in NavigationLink(value: folder) { Text(folder.name) } } } } } To reproduce the bug, just tap on one of the item. Oddly enough, this works fine in the Simulator. macOS 14 beta 5 is not affected either. Apple folks: FB12981860
16
2
4.2k
Oct ’23
Cannot use instance member 'golfData' within property initializer; property initializers run before 'self' is available ?
******* TestData.swift ************************ struct Measures: Identifiable { let id = UUID() var dataSeq: Int var value: Double } struct Items: Identifiable { let id = UUID() var name: String var measures: [Measures] } struct chartItemInfo: Identifiable { var id = UUID() var testItem: String var value: Double } var angleItem : [chartItemInfo]? var degreeItem : [chartItemInfo]? var grip1Item : [chartItemInfo]? var grip2Item : [chartItemInfo]? class TestData: ObservableObject { @Published var angleItem : [chartItemInfo]? @Published var degreeItem : [chartItemInfo]? @Published var grip1Item : [chartItemInfo]? @Published var grip2Item : [chartItemInfo]? } ******** CalculatorViewModel.swift ****************************************** class CalculatorViewModel : NSObject, ObservableObject, Identifiable { .... typealias test_Array = (time: String, swingNum: Int, dataSeqInSwing: Int, timeStampInSeq: Int, angle: Double, degree: Double, grip1: Double, grip2: Double) .... @Published var testDBdata = [test_Array]() @Published var chartDBdata = [chart_Array]() // @StateObject var testData : TestData var Testitems = [ (channel: "angle", data: testData.angleItem), (channel: "degree", data: testData.degreeItem), (channel: "grip1", data: testData.grip1Item), (channel: "grip2", data: testData.grip2Item)]. => Cannot use instance member 'testData' within property initializer; property initializers run before 'self' is available ? purpose of this project: read FMDB data and then make Array with DB data. and then i use these Array for displaying multi plot in Chart.
1
0
776
Oct ’23
iOS 17 @Obervable object - how to make it lazy to init once for the identical view?
iOS 17 introduced @Observable. that's an effective way to implement a stateful model object. however, we will not be able to use @StateObject as the model object does not have ObservableObject protocol. An advantage of using StateObject is able to make the object initializing once only for the view. it will keep going on until the view identifier is changed. I put some examples. We have a Observable implemented object. @Observable final class Controller { ... } then using like this struct MyView: View { let controller: Controller init(value: Value) { self.controller = .init(value: value) } init(controller: Controller) { self.controller = controller } } this case causes a problem that the view body uses the passed controller anyway. even passed different controller, uses it. and what if initializing a controller takes some costs, that decrease performance. how do we manage this kind of use case? anyway I made a utility view that provides an observable object lazily. public struct ObjectProvider<Object, Content: View>: View { @State private var object: Object? private let _objectInitializer: () -> Object private let _content: (Object) -> Content public init(object: @autoclosure @escaping () -> Object, @ViewBuilder content: @escaping (Object) -> Content) { self._objectInitializer = object self._content = content } public var body: some View { Group { if let object = object { _content(object) } } .onAppear { object = _objectInitializer() } } } ObjectProvider(object: Controller() { controller in MyView(controller: controller) } for now it's working correctly.
1
0
1k
Oct ’23
How to observe changes to properties of an @Observable from another non-view class?
I have a class A and class B, and both of them are @Observable, and none of them are a view. Class A has an instance of class B. I want to be able to listen to changes in this instance of class B, from my class A. Previously, by using ObservableObject, instead of the @Observable macro, every property that needed to be observable, had to be declared as a Publisher. With this new framework, everything seems to be automatically synthesised, and using a Publisher is no longer required, as all the properties are observable. That being said, how can I have an equivalent using @Observable? Is this new macro only for view-facing classes?
1
1
1.4k
Sep ’23
@StateObject for view owning "viewModel" to use with @Observable observation framework object
I have an issue with a View that owns @Observable object (Instantize it, and is owner during the existence) in the same notion as @StateObject, however when @State is used the viewModel is re-created and deallocated on every view redraw. In the previous models, @StateObject were used when the View is owner of the object (Owner of the viewModel as example) When @Observable object is used in the same notion, @State var viewModel = ViewModel() the viewModel instance is recreated on views redraws. @StateObject was maintaining the same instance during the View existence, that however is not happening when used @Observable with @State.
2
1
2.1k
Sep ’23
SwiftData Model class not triggering observation of computed property that depends on relationship
I created FB13074428 and a small sample project to demonstrate the bug. https://github.com/jamiemcd/Apple-FB13074428 Basically, if a SwiftData class is marked as @Model and it has a computed property that depends on a relationship's stored property, the computed property does not trigger updates in SwiftUI when the underlying relationship changes its stored property. This is Xcode 15 Beta 8. @Model final class Airport { var code: String var name: String var airplanes: [Airplane] init(code: String, name: String, airPlanes: [Airplane]) { self.code = code self.name = name self.airplanes = airPlanes } // Bug: This computed property is not triggering observation in AirportView when airplane.state changes. My understanding of the new observation framework is that it should. var numberOfAirplanesDeparting: Int { var numberOfAirplanesDeparting = 0 for airplane in airplanes { if airplane.state == .departing { numberOfAirplanesDeparting += 1 } } return numberOfAirplanesDeparting } } AirportView should update because it has Text for airport.numberOfAirplanesDeparting struct AirportView: View { var airport: Airport var body: some View { List { Section { ForEach(airport.airplanes) { airplane in NavigationLink(value: airplane) { HStack { Image(systemName: airplane.state.imageSystemName) VStack(alignment: .leading) { Text(airplane.name) Text(airplane.type.name) } } } } } header: { Text(airport.name) } footer: { VStack(alignment: .leading) { Text("Planes departing = \(airport.numberOfAirplanesDeparting)") Text("Planes in flight = \(airport.numberOfAirplanesInFlight)") Text("Planes landing = \(airport.numberOfAirplanesLanding)") } } } }
4
3
2.1k
Sep ’23
SwiftData - What is Best Practice for returning an object from a sheet
SwiftUI & SwiftData. I have a view that lists SwiftData objects. Tapping on a list item navigates to a detail view. The list view also has a "New Object" button. Tapping it opens a sheet used to create a new object. There are, obviously, two possible outcomes from interacting with the sheet — a new object could be created or the user could cancel without creating a new object. If the user creates a new object using the sheet, I want to open the detail view for that object. My thought was to do this in the onDismiss handler for the sheet. However, that handler takes no arguments. What is best practice for handling this situation? In UIKit, I would return a Result<Object, Error> in a closure. That won't work here. What is the "correct" way to handle this that is compatible with SwiftData and the Observation framework?
2
0
2.1k
Aug ’23
NavigationSplitView crashes in Xcode, iOS Beta 7
I have a NavigationSplitView with a sidebar. When selecting a new item on the sidebar, the app crashes. The error message says: Simultaneous accesses to 0x6000030107f0, but modification requires exclusive access. Xcode shows that the crash occurs inside the generated code in my class with @Observable macro. @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() internal nonisolated func access<Member>( keyPath: KeyPath<NavModel , Member> ) { _$observationRegistrar.access(self, keyPath: keyPath) } internal nonisolated func withMutation<Member, MutationResult>( keyPath: KeyPath<NavModel , Member>, _ mutation: () throws -> MutationResult ) rethrows -> MutationResult { // Crash occurs on the following line try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) } @ObservationIgnored private var _section: SidebarSection? = .one To reproduce the crash, I tap a new item on the sidebar until the app crashes. It usually only takes 1-3 times selecting a new item before the crash occurs. Below is the code for an entire app to reproduce the crash. Has anyone else encountered this issue? Thank you! import SwiftUI @main struct NavigationBugApp: App { var body: some Scene { WindowGroup { ContentView() } } } @Observable class NavModel { var section: SidebarSection? = .one } enum SidebarSection: Hashable { case one case two } struct ContentView: View { @State private var model = NavModel() var body: some View { NavigationSplitView { List(selection: $model.section) { NavigationLink("One", value: SidebarSection.one) NavigationLink("Two", value: SidebarSection.two) } .listStyle(.sidebar) } detail: { Text("Hello World") } } } #Preview { ContentView() }
2
0
1.4k
Aug ’23
Trouble with Persisting One-to-Many Relationship Data in SwiftData, What am I Missing?
Hi everyone, I'm new to programming and I've been experimenting with Apple's SwiftData. I've run into an issue I can't seem to resolve. I'm creating a personal relationship manager app where I have a Relation model and an Interaction model. Relation has a one-to-many relationship with Interaction. I'm using SwiftData's @Model and @Relationship property wrappers to define these models and their relationship. I've taken inspiration from Apple's sample code, that can be found here: Adopting SwiftData for a Core Data app (WWDC23 Session: "Migrate to SwiftData") The relevant parts of the models look something like this: @Model final class Relation { ... @Relationship(.cascade, inverse: \Interaction.relation) var interactions: [Interaction] = [] ... } @Model final class Interaction { ... var relation: Relation? ... } In my SwiftUI view, I'm adding a new Interaction to a Relation like this: private func AddItem() { withAnimation { let newInteraction = Interaction(...) modelContext.insert(newInteraction) newInteraction.relation = relation relation.interactions.append(newInteraction) } } When I add a new Interaction like this, everything seems to work fine during that app session. I can see the new Interaction in my app's UI. But when I quit the app and relaunch it, the new Interaction is gone. It's as if it was never saved. I've double-checked my code and as far as I can tell, I'm using SwiftData correctly. My usage aligns with the sample code provided by Apple, and I'm not getting any errors or warnings. I think that this issue is not related to SwiftData being in Beta, because Apple's sample code works perfectly fine. I have a few questions: Is there something I'm missing about how to properly save models using SwiftData? Is there a specific step or method I need to call to persist the changes to the Relation and Interaction objects? Is there a way to debug what's going wrong when SwiftData attempts to save these changes? Any help would be greatly appreciated. Thank you in advance! Louis
2
0
2.8k
Aug ’23
can't use @Environment for Binding?
@Environment can't use for Binding? @Observable final class View1Model { var text: String = "" } struct View1: View { @State var viewModel = View1Model() var body: some View { View2() .environment(viewModel) } } struct View2: View { @Environment(View1Model.self) var viewModel var body: some View { TextField("Text", text: $viewModel.text) // Cannot find '$viewModel' in scope } }
6
2
6.2k
Aug ’23
@Observable not working in Xcode playgrounds
Creating an Observable class in an Xcode playground seems to cause an error. This stops me from being able to run the playground. As a demo, try creating a playground page and add: import Foundation import Observation // Doesn't seem to make a difference whether it's added or not. @Observable public class NewViewModel: Observable { var value: Int = 1 func increment() { value += 1 } } Tapping the run button logs the following error (and then it builds successfully, buy fails silently): error: Untitled Page.xcplaygroundpage:7:9: error: expansion of macro 'ObservationTracked()' did not produce a non-observing accessor var value: Int = 1 ^ Putting the cursor on @Observable and then selecting Editor > Expand Macro shows that value has been annotated with @ObservationTracked and I if I re-run the playground I can even see the @ObservationTracked generated code. Macros: import Foundation import Observation // Doesn't seem to make a difference whether it's added or not. @Observable public class NewViewModel: Observable { @ObservationTracked // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:7:5-7:5 var value: Int = 1 { @storageRestrictions(initializes: _value) init(initialValue) { _value = initialValue } get { access(keyPath: \.value) return _value } set { withMutation(keyPath: \.value) { _value = newValue } } } // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:7:20-7:23 func increment() { value += 1 } @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() internal nonisolated func access<Member>( keyPath: KeyPath<NewViewModel, Member> ) { _$observationRegistrar.access(self, keyPath: keyPath) } internal nonisolated func withMutation<Member, MutationResult>( keyPath: KeyPath<NewViewModel, Member>, _ mutation: () throws -> MutationResult ) rethrows -> MutationResult { try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) } @ObservationIgnored private var _value: Int = 1 // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:12:1-12:1 } I can't seem to be able to expand the @ObservationIgnored macros, which may or may not be related to the issue. I can't expand them in a regular Xcode app, but it doesn't lead to any problems there. Im running an iOS playground. I get this in Xcodes 15 beta 6 and 5. I get a different error in earlier versions.
1
0
1.5k
Aug ’23
Use multiple @Observable inside each other using @Enviroment
Hello I'm trying the new Observation in SwiftUI, I created 2 classes using the new @Observable wrapper like this: @Observable class CategoriesViewModel { var categories: [Category] = [] } @Observable class NotesViewModel { var notes: [Note] = [] } and I'm using them in the views like this: @Environment(CategoriesViewModel.self) var categoriesViewModel The question is: what if I want to use an observable inside another observable ? for example, I want to use the categories inside the NotesViewModel, I tried the @State instead of @Enviroment but it's not a global across all classes, so I want to use it as an environment variable like what I did in the views, I tried to use it inside the Observable class like this but I got an error below: @Observable class NotesViewModel { var notes: [Note] = [] @ObservationIgnored @Environment(CategoriesViewModel.self) var categoriesViewModel: CategoriesViewModel func foo(){ /// Thread 1: Fatal error: No Observable object of type CategoriesViewModel found. A View.environmentObject(_:) for CategoriesViewModel may be missing as an ancestor of this view. print(categoriesViewModel.categories.count) } }
1
0
1.3k
Aug ’23
Mix new @Observable with MVVM and Combine
We currently have our entire app written as SwiftUI Views with ViewModels (currently set as @StateObjects). SwiftUI has a new feature in iOS 17 called @Observable which simplifies the MVVM pattern and would greatly reduce the complexity of our codebase. However, our current ViewModels implement Combine pipelines on the @Published properties which allows us to do all sorts of things from validation of inputs to ensuring lists are filtered correctly. Without the @Published property wrapper in the new @Observable macro, we don't have access to those combine pipelines and so we were wondering how others have solved this? One idea we are floating around is using CurrentValueSubjects as the variable types, but that does pollute the code a little as we have to utilise .send() and .value in the Views which seems like an anti-pattern. Any thoughts or help would be greatly appreciated!
2
3
1.9k
Aug ’23
Swift compiler crash in Xcode 15 beta 3 (15A5195k)
Somehow the Swift compiler is unable to this code: @Observable class ServiceBrowser: NSObject { typealias ResolveServiceCompletionBlock = (Bool, Error?) -> Void fileprivate var resolveServiceCompletionHandler: ResolveServiceCompletionBlock? = nil } Here's the crash: 4 . While evaluating request ASTLoweringRequest(Lowering AST to SIL for file "/Users/luc/Work/Repositories/app-shared/App/Shared/Connectivity/ServiceBrowser.swift") 5 . While silgen init accessor SIL function "@$s7App14ServiceBrowserC07resolveB17CompletionHandler33_5B15C352D9CC926D1F8A0ECAC5970199LLySb_s5Error_pSgtcSgvi". for init for resolveServiceCompletionHandler (at /Users/luc/Work/Repositories/ap-shared/App/Shared/Connectivity/ServiceBrowser.swift:86:21) 6 . While emitting reabstraction thunk in SIL function "@$sSbs5Error_pSgIegyg_ytIegd_TR".
2
0
1.3k
Jul ’23
Bindable is never deallocated
I've encountered a problem which I don't know if is related to swiftui, the observation framework, or both If I run the following code I have two tabs, with the second tab that use a "lazy model" which is deallocated each time disappears (this is necessary for my use case) If I switch to the second tab, all works right. If I return to the first tab, the onDisappear on the foo view should force the "Bar" variable to nil , because the FooView may be still allocated (it is a tab bar) but that resource should be released If that bar variable is set to nil, the MyBar should be replaced by the ProgressView in the "background" I expect regarding that the Bar that: the instance is nil on Foo no other view should be shown with that instance (MyBar is now disappeared) Because no ref, the Bar observable object should be now deallocated In reality the Bar object is still in my memory graph Any suggestions? is it a bug? @Observable class Bar { var hello: String = "" } struct Foo: View { @State var bar: Bar? @ViewBuilder private var content: some View { if let bar { MyBar(bar: bar) } else { ProgressView() } } var body: some View { content .onAppear { bar = Bar() } .onDisappear { self.bar = nil } } } struct MyBar: View { @Bindable var bar: Bar var body: some View { Text("MyBar") } } struct ContentView: View { @State var tag: Int = 0 var body: some View { TabView(selection: $tag) { Text("First") .tag(0) .tabItem { Text("First") } Foo() .tag(1) .tabItem { Text("Foo") } } } }
Replies
1
Boosts
0
Views
879
Activity
Nov ’23
SwiftUI: Grandparent View Not Updating on Model Change in SwiftData
I'm working on a SwiftUI app using SwiftData for state management. I've encountered an issue with view updates when mutating a model. Here's a minimal example to illustrate the problem: import SwiftUI import SwiftData // MARK: - Models @Model class A { @Relationship var bs: [B] = [B]() init(bs: [B]) { self.bs = bs } } @Model class B { @Relationship var cs: [C] = [C]() init(cs: [C]) { self.cs = cs } } @Model class C { var done: Bool init(done: Bool) { self.done = done } } // MARK: - Views struct CView: View { var c: C var body: some View { @Bindable var c = c HStack { Toggle(isOn: $c.done, label: { Text("Done") }) } } } struct BView: View { var b: B var body: some View { List(b.cs) { c in CView(c: c) } } } struct AView: View { var a: A var body: some View { List(a.bs) { b in NavigationLink { BView(b: b) } label: { Text("B \(b.cs.allSatisfy({ $0.done }).description)") } } } } struct ContentView: View { @Query private var aList: [A] var body: some View { NavigationStack { List(aList) { a in NavigationLink { AView(a: a) } label: { Text("A \(a.bs.allSatisfy({ $0.cs.allSatisfy({ $0.done }) }).description)") } } } } } @main struct Minimal: App { var body: some Scene { WindowGroup { ContentView() } } } #Preview { let config = ModelConfiguration(isStoredInMemoryOnly: true) let container = try! ModelContainer(for: A.self, configurations: config) var c = C(done: false) container.mainContext.insert(c) var b = B(cs: [c]) container.mainContext.insert(b) var a = A(bs: [b]) container.mainContext.insert(a) return ContentView() .modelContainer(container) } In this setup, I have a CView where I toggle the state of a model C. After toggling C and navigating back, the grandparent view AView does not reflect the updated state (it still shows false instead of true). However, if I navigate back to the root ContentView and then go to AView, the status is updated correctly. Why doesn't AView update immediately after mutating C in CView, but updates correctly when navigating back to the root ContentView? I expected the grandparent view to reflect the changes immediately as per SwiftData's observation mechanism.
Replies
1
Boosts
1
Views
797
Activity
Nov ’23
[SwiftData] Bugs with `autosaveEnabled` and `undoManager` + Observation
Hello, my goal is it to implement an Edit Sheet of a Model with Discard changes in SwiftData. Xcode Version 15.0 beta 6 (15A5219j) Approaches In the following modelContext refers to the context fetched from the environment by the View. Also code for showing the sheet (eg. toggling isPresented) is omitted. // App ContentView() .modelContainer(for: Model.self, isAutosaveEnabled: true, isUndoEnabled: true) // In Content View @Query var models: [Model] //... ForEach(models) { model in ModelView(model: model) //eg. longpresgesture that calls openEditSheet .sheet(..., content: { EditModelView(model: model) } } Disabling autosave + rollback // In ContentView func openEditSheet() { modelContext.autosaveEnabled = false } // In EditModelView func discardEditSheet() { modelContext.rollback() modelContext.autosaveEnabled = true } func saveEditSheet() { try? modelContext.save() // probably not needed if autosave gets enabled anyway modelContext.autosaveEnabled = true } However this approach does not work, as SwiftData continues to save anyway and therefore there is nothing to rollback. modelContext in Memory // In ContentView let context = ModelContext(modelContext.container) context.autosaveEnabled = false context.container.configuration.removeAll() context.container.configuration.insert(ModelConfiguration(..., inMemory: true) //... EditModelView() .modelContext(context) // Also tried: .enviroment(\.modelContext, context) // In EditModelView func discardEditSheet() { modelContext.rollback() // probably not needed as the container is never saved } func saveEditSheet() { try? modelContext.save() // move to persistent storage from memory } The idea was to use something like parent in CoreData. However as this is (currently) not supported. Also tried this by modifying the modelContext directly (instead of creating a new context) and its container directly or before creating the context. The child can not be a ModelContainer as you can not pass a context to it or set its mainContext (get-only). However this approach does not work, as the container does not seem to stay in memory. Maybe related to previous. BackingData EditModelView(model: Model(backingData: model.persistentBackingData) not sure about this one, played around a little with it but not sure what it means / should mean and how I would expect it to work. I have never been great at cooking :). UndoManager (preferred) // In ContentView func openEditSheet() { modelContext.undoManager?.beginUndoGrouping() } // In EditModelView func discardEditSheet() { modelContext.undoManager?.endUndoGrouping() modelContext.undoManager?.undoNestedGroup() // Also tried adding: try? modelContext.save() } func saveEditSheet() { modelContext.undoManager?.endUndoGrouping() } This approach does works kinda weird: The ModelView of the updated model in ContentView's ForEach is not updated regarding the undo action. However when I re-open the EditTaskView of the updated model it has the expected state, even though the model to edit is passed by the ContentView (which does not have the correct state?). After relaunching the app or when modifying the model again (this time not undoing) the previous sate changes are recognised Therefore this looks like it does what I want, with the ContentView having the correct state, but not displaying it. Only reason I can think of is the Model: Observable not getting triggered and therefore no View update. Conclusion After playing around with the above approaches and combining them in every possible way, i think that: disabling autosave at runtime is currently not working and this is a bug (otherwise autosaveEnabled should be get-only). UndoManager does not trigger a View update of a Model/Observable and this is a bug Would be happy to hear other opinions on this. Am I missing something here? Am I ******? Question However as my conclusion does not fix my problem I am wondering: Are my approaches (theoretically) correct? How do I fix / workaround the UndoManager issue? If I identified it correctly, how can I manually notify the view that a Observable model has changed?
Replies
3
Boosts
3
Views
2.2k
Activity
Nov ’23
When I create an object, the view is updated, but when I update data inside that object, the view is not updated
class PostManager: ObservableObject { static let shared = PostManager() private init() {} @Published var containers: [PostContainer] = [] // Other code } class PostContainer: ObservableObject { var id: UUID = UUID() var timestamp: Date var subreddit: String var posts: [Post] var type: ContainerType var active: Bool // Init } @Model final class Post: Decodable, ObservableObject { // Other code } In my main view, a network request is made and a PostContainer is created if it doesn't exist. This code works fine, and the view is updated correctly. let container = PostContainer(timestamp: Date(), subreddit: subreddit, posts: posts, type: .search, active: true) self.containers.append(container) If the user wants to see more, they press a button and another request is made. This time, the new data will be added to the PostContainer instead of creating a new one. if let container = self.containers.first(where: {$0.subreddit == subreddit}) { // Update previous container container.timestamp = Date() print(container.posts.count) // Map IDs from container and then remove duplicates let existingIDs = Set(container.posts.map { $0.id }) let filtered = posts.filter { !existingIDs.contains($0.id) } // Append new post container.posts.append(contentsOf: filtered) container.active = true } This code is working fine as well, except for the view is not updating. In the view, PostManager is an @EnvironmentObject. I also have a computed variable to get the post and sort them. I added a print statement to that variable and saw that it wasn't being printed even though more data was being added to the PostContainer. At one point, I created an ID for the List that displays the data and had the code inside PostManager update that ID when it was finished. This of course worked, but it's not ideal. How can I get the view to update when post are appended inside of PostContainer?
Replies
1
Boosts
0
Views
605
Activity
Nov ’23
iOS 17b6: Simultaneous accesses to ..., but modification requires exclusive access crash using Observation and SwiftUI
Since iOS/iPadOS beta 6, I get a crash just by simply selecting an item in the sidebar of a navigation view. The selected item is part of an app mode, with conforms to the Observation protocol: import SwiftUI import Observation @main struct MREAApp: App { @State private var appModel = AppModel.shared var body: some Scene { WindowGroup { ContentView() .environment(appModel) } } } @Observable class AppModel { static var shared = AppModel() var selectedFolder: Folder? = nil } struct Folder: Hashable, Identifiable { let id = UUID() let name: String } struct ContentView: View { @Environment(AppModel.self) private var appModel var folders = [Folder(name: "Recents"), Folder(name: "Deleted"), Folder(name: "Custom")] var body: some View { NavigationSplitView { SidebarView(appModel: appModel, folders: folders) } detail: { if let folder = appModel.selectedFolder { Text(folder.name) } else { Text("No selection") } } } } struct SidebarView: View { @Bindable var appModel: AppModel var folders: [Folder] var body: some View { List(selection: $appModel.selectedFolder) { ForEach(folders, id: \.self) { folder in NavigationLink(value: folder) { Text(folder.name) } } } } } To reproduce the bug, just tap on one of the item. Oddly enough, this works fine in the Simulator. macOS 14 beta 5 is not affected either. Apple folks: FB12981860
Replies
16
Boosts
2
Views
4.2k
Activity
Oct ’23
Cannot use instance member 'golfData' within property initializer; property initializers run before 'self' is available ?
******* TestData.swift ************************ struct Measures: Identifiable { let id = UUID() var dataSeq: Int var value: Double } struct Items: Identifiable { let id = UUID() var name: String var measures: [Measures] } struct chartItemInfo: Identifiable { var id = UUID() var testItem: String var value: Double } var angleItem : [chartItemInfo]? var degreeItem : [chartItemInfo]? var grip1Item : [chartItemInfo]? var grip2Item : [chartItemInfo]? class TestData: ObservableObject { @Published var angleItem : [chartItemInfo]? @Published var degreeItem : [chartItemInfo]? @Published var grip1Item : [chartItemInfo]? @Published var grip2Item : [chartItemInfo]? } ******** CalculatorViewModel.swift ****************************************** class CalculatorViewModel : NSObject, ObservableObject, Identifiable { .... typealias test_Array = (time: String, swingNum: Int, dataSeqInSwing: Int, timeStampInSeq: Int, angle: Double, degree: Double, grip1: Double, grip2: Double) .... @Published var testDBdata = [test_Array]() @Published var chartDBdata = [chart_Array]() // @StateObject var testData : TestData var Testitems = [ (channel: "angle", data: testData.angleItem), (channel: "degree", data: testData.degreeItem), (channel: "grip1", data: testData.grip1Item), (channel: "grip2", data: testData.grip2Item)]. => Cannot use instance member 'testData' within property initializer; property initializers run before 'self' is available ? purpose of this project: read FMDB data and then make Array with DB data. and then i use these Array for displaying multi plot in Chart.
Replies
1
Boosts
0
Views
776
Activity
Oct ’23
iOS 17 @Obervable object - how to make it lazy to init once for the identical view?
iOS 17 introduced @Observable. that's an effective way to implement a stateful model object. however, we will not be able to use @StateObject as the model object does not have ObservableObject protocol. An advantage of using StateObject is able to make the object initializing once only for the view. it will keep going on until the view identifier is changed. I put some examples. We have a Observable implemented object. @Observable final class Controller { ... } then using like this struct MyView: View { let controller: Controller init(value: Value) { self.controller = .init(value: value) } init(controller: Controller) { self.controller = controller } } this case causes a problem that the view body uses the passed controller anyway. even passed different controller, uses it. and what if initializing a controller takes some costs, that decrease performance. how do we manage this kind of use case? anyway I made a utility view that provides an observable object lazily. public struct ObjectProvider<Object, Content: View>: View { @State private var object: Object? private let _objectInitializer: () -> Object private let _content: (Object) -> Content public init(object: @autoclosure @escaping () -> Object, @ViewBuilder content: @escaping (Object) -> Content) { self._objectInitializer = object self._content = content } public var body: some View { Group { if let object = object { _content(object) } } .onAppear { object = _objectInitializer() } } } ObjectProvider(object: Controller() { controller in MyView(controller: controller) } for now it's working correctly.
Replies
1
Boosts
0
Views
1k
Activity
Oct ’23
How to observe changes to properties of an @Observable from another non-view class?
I have a class A and class B, and both of them are @Observable, and none of them are a view. Class A has an instance of class B. I want to be able to listen to changes in this instance of class B, from my class A. Previously, by using ObservableObject, instead of the @Observable macro, every property that needed to be observable, had to be declared as a Publisher. With this new framework, everything seems to be automatically synthesised, and using a Publisher is no longer required, as all the properties are observable. That being said, how can I have an equivalent using @Observable? Is this new macro only for view-facing classes?
Replies
1
Boosts
1
Views
1.4k
Activity
Sep ’23
@StateObject for view owning "viewModel" to use with @Observable observation framework object
I have an issue with a View that owns @Observable object (Instantize it, and is owner during the existence) in the same notion as @StateObject, however when @State is used the viewModel is re-created and deallocated on every view redraw. In the previous models, @StateObject were used when the View is owner of the object (Owner of the viewModel as example) When @Observable object is used in the same notion, @State var viewModel = ViewModel() the viewModel instance is recreated on views redraws. @StateObject was maintaining the same instance during the View existence, that however is not happening when used @Observable with @State.
Replies
2
Boosts
1
Views
2.1k
Activity
Sep ’23
SwiftData Model class not triggering observation of computed property that depends on relationship
I created FB13074428 and a small sample project to demonstrate the bug. https://github.com/jamiemcd/Apple-FB13074428 Basically, if a SwiftData class is marked as @Model and it has a computed property that depends on a relationship's stored property, the computed property does not trigger updates in SwiftUI when the underlying relationship changes its stored property. This is Xcode 15 Beta 8. @Model final class Airport { var code: String var name: String var airplanes: [Airplane] init(code: String, name: String, airPlanes: [Airplane]) { self.code = code self.name = name self.airplanes = airPlanes } // Bug: This computed property is not triggering observation in AirportView when airplane.state changes. My understanding of the new observation framework is that it should. var numberOfAirplanesDeparting: Int { var numberOfAirplanesDeparting = 0 for airplane in airplanes { if airplane.state == .departing { numberOfAirplanesDeparting += 1 } } return numberOfAirplanesDeparting } } AirportView should update because it has Text for airport.numberOfAirplanesDeparting struct AirportView: View { var airport: Airport var body: some View { List { Section { ForEach(airport.airplanes) { airplane in NavigationLink(value: airplane) { HStack { Image(systemName: airplane.state.imageSystemName) VStack(alignment: .leading) { Text(airplane.name) Text(airplane.type.name) } } } } } header: { Text(airport.name) } footer: { VStack(alignment: .leading) { Text("Planes departing = \(airport.numberOfAirplanesDeparting)") Text("Planes in flight = \(airport.numberOfAirplanesInFlight)") Text("Planes landing = \(airport.numberOfAirplanesLanding)") } } } }
Replies
4
Boosts
3
Views
2.1k
Activity
Sep ’23
SwiftData - What is Best Practice for returning an object from a sheet
SwiftUI & SwiftData. I have a view that lists SwiftData objects. Tapping on a list item navigates to a detail view. The list view also has a "New Object" button. Tapping it opens a sheet used to create a new object. There are, obviously, two possible outcomes from interacting with the sheet — a new object could be created or the user could cancel without creating a new object. If the user creates a new object using the sheet, I want to open the detail view for that object. My thought was to do this in the onDismiss handler for the sheet. However, that handler takes no arguments. What is best practice for handling this situation? In UIKit, I would return a Result<Object, Error> in a closure. That won't work here. What is the "correct" way to handle this that is compatible with SwiftData and the Observation framework?
Replies
2
Boosts
0
Views
2.1k
Activity
Aug ’23
NavigationSplitView crashes in Xcode, iOS Beta 7
I have a NavigationSplitView with a sidebar. When selecting a new item on the sidebar, the app crashes. The error message says: Simultaneous accesses to 0x6000030107f0, but modification requires exclusive access. Xcode shows that the crash occurs inside the generated code in my class with @Observable macro. @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() internal nonisolated func access<Member>( keyPath: KeyPath<NavModel , Member> ) { _$observationRegistrar.access(self, keyPath: keyPath) } internal nonisolated func withMutation<Member, MutationResult>( keyPath: KeyPath<NavModel , Member>, _ mutation: () throws -> MutationResult ) rethrows -> MutationResult { // Crash occurs on the following line try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) } @ObservationIgnored private var _section: SidebarSection? = .one To reproduce the crash, I tap a new item on the sidebar until the app crashes. It usually only takes 1-3 times selecting a new item before the crash occurs. Below is the code for an entire app to reproduce the crash. Has anyone else encountered this issue? Thank you! import SwiftUI @main struct NavigationBugApp: App { var body: some Scene { WindowGroup { ContentView() } } } @Observable class NavModel { var section: SidebarSection? = .one } enum SidebarSection: Hashable { case one case two } struct ContentView: View { @State private var model = NavModel() var body: some View { NavigationSplitView { List(selection: $model.section) { NavigationLink("One", value: SidebarSection.one) NavigationLink("Two", value: SidebarSection.two) } .listStyle(.sidebar) } detail: { Text("Hello World") } } } #Preview { ContentView() }
Replies
2
Boosts
0
Views
1.4k
Activity
Aug ’23
Trouble with Persisting One-to-Many Relationship Data in SwiftData, What am I Missing?
Hi everyone, I'm new to programming and I've been experimenting with Apple's SwiftData. I've run into an issue I can't seem to resolve. I'm creating a personal relationship manager app where I have a Relation model and an Interaction model. Relation has a one-to-many relationship with Interaction. I'm using SwiftData's @Model and @Relationship property wrappers to define these models and their relationship. I've taken inspiration from Apple's sample code, that can be found here: Adopting SwiftData for a Core Data app (WWDC23 Session: "Migrate to SwiftData") The relevant parts of the models look something like this: @Model final class Relation { ... @Relationship(.cascade, inverse: \Interaction.relation) var interactions: [Interaction] = [] ... } @Model final class Interaction { ... var relation: Relation? ... } In my SwiftUI view, I'm adding a new Interaction to a Relation like this: private func AddItem() { withAnimation { let newInteraction = Interaction(...) modelContext.insert(newInteraction) newInteraction.relation = relation relation.interactions.append(newInteraction) } } When I add a new Interaction like this, everything seems to work fine during that app session. I can see the new Interaction in my app's UI. But when I quit the app and relaunch it, the new Interaction is gone. It's as if it was never saved. I've double-checked my code and as far as I can tell, I'm using SwiftData correctly. My usage aligns with the sample code provided by Apple, and I'm not getting any errors or warnings. I think that this issue is not related to SwiftData being in Beta, because Apple's sample code works perfectly fine. I have a few questions: Is there something I'm missing about how to properly save models using SwiftData? Is there a specific step or method I need to call to persist the changes to the Relation and Interaction objects? Is there a way to debug what's going wrong when SwiftData attempts to save these changes? Any help would be greatly appreciated. Thank you in advance! Louis
Replies
2
Boosts
0
Views
2.8k
Activity
Aug ’23
can't use @Environment for Binding?
@Environment can't use for Binding? @Observable final class View1Model { var text: String = "" } struct View1: View { @State var viewModel = View1Model() var body: some View { View2() .environment(viewModel) } } struct View2: View { @Environment(View1Model.self) var viewModel var body: some View { TextField("Text", text: $viewModel.text) // Cannot find '$viewModel' in scope } }
Replies
6
Boosts
2
Views
6.2k
Activity
Aug ’23
@Observable not working in Xcode playgrounds
Creating an Observable class in an Xcode playground seems to cause an error. This stops me from being able to run the playground. As a demo, try creating a playground page and add: import Foundation import Observation // Doesn't seem to make a difference whether it's added or not. @Observable public class NewViewModel: Observable { var value: Int = 1 func increment() { value += 1 } } Tapping the run button logs the following error (and then it builds successfully, buy fails silently): error: Untitled Page.xcplaygroundpage:7:9: error: expansion of macro 'ObservationTracked()' did not produce a non-observing accessor var value: Int = 1 ^ Putting the cursor on @Observable and then selecting Editor > Expand Macro shows that value has been annotated with @ObservationTracked and I if I re-run the playground I can even see the @ObservationTracked generated code. Macros: import Foundation import Observation // Doesn't seem to make a difference whether it's added or not. @Observable public class NewViewModel: Observable { @ObservationTracked // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:7:5-7:5 var value: Int = 1 { @storageRestrictions(initializes: _value) init(initialValue) { _value = initialValue } get { access(keyPath: \.value) return _value } set { withMutation(keyPath: \.value) { _value = newValue } } } // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:7:20-7:23 func increment() { value += 1 } @ObservationIgnored private let _$observationRegistrar = Observation.ObservationRegistrar() internal nonisolated func access<Member>( keyPath: KeyPath<NewViewModel, Member> ) { _$observationRegistrar.access(self, keyPath: keyPath) } internal nonisolated func withMutation<Member, MutationResult>( keyPath: KeyPath<NewViewModel, Member>, _ mutation: () throws -> MutationResult ) rethrows -> MutationResult { try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation) } @ObservationIgnored private var _value: Int = 1 // original-source-range: /Users/gabriel.banfalvi/work/forums_observation/ObservationFramework.playground/Pages/Untitled Page.xcplaygroundpage:12:1-12:1 } I can't seem to be able to expand the @ObservationIgnored macros, which may or may not be related to the issue. I can't expand them in a regular Xcode app, but it doesn't lead to any problems there. Im running an iOS playground. I get this in Xcodes 15 beta 6 and 5. I get a different error in earlier versions.
Replies
1
Boosts
0
Views
1.5k
Activity
Aug ’23
How to Debounce and Throttle Using @Observable
I want to transition from Combine to the Observation framework my question is how do I Debounce user input with the Observation framework there appears now way to do this. Any and all help is welcomed.
Replies
4
Boosts
2
Views
3k
Activity
Aug ’23
Use multiple @Observable inside each other using @Enviroment
Hello I'm trying the new Observation in SwiftUI, I created 2 classes using the new @Observable wrapper like this: @Observable class CategoriesViewModel { var categories: [Category] = [] } @Observable class NotesViewModel { var notes: [Note] = [] } and I'm using them in the views like this: @Environment(CategoriesViewModel.self) var categoriesViewModel The question is: what if I want to use an observable inside another observable ? for example, I want to use the categories inside the NotesViewModel, I tried the @State instead of @Enviroment but it's not a global across all classes, so I want to use it as an environment variable like what I did in the views, I tried to use it inside the Observable class like this but I got an error below: @Observable class NotesViewModel { var notes: [Note] = [] @ObservationIgnored @Environment(CategoriesViewModel.self) var categoriesViewModel: CategoriesViewModel func foo(){ /// Thread 1: Fatal error: No Observable object of type CategoriesViewModel found. A View.environmentObject(_:) for CategoriesViewModel may be missing as an ancestor of this view. print(categoriesViewModel.categories.count) } }
Replies
1
Boosts
0
Views
1.3k
Activity
Aug ’23
Mix new @Observable with MVVM and Combine
We currently have our entire app written as SwiftUI Views with ViewModels (currently set as @StateObjects). SwiftUI has a new feature in iOS 17 called @Observable which simplifies the MVVM pattern and would greatly reduce the complexity of our codebase. However, our current ViewModels implement Combine pipelines on the @Published properties which allows us to do all sorts of things from validation of inputs to ensuring lists are filtered correctly. Without the @Published property wrapper in the new @Observable macro, we don't have access to those combine pipelines and so we were wondering how others have solved this? One idea we are floating around is using CurrentValueSubjects as the variable types, but that does pollute the code a little as we have to utilise .send() and .value in the Views which seems like an anti-pattern. Any thoughts or help would be greatly appreciated!
Replies
2
Boosts
3
Views
1.9k
Activity
Aug ’23
Platform specific property in Observable
With the following in an iOS and watch app import Observation @Observable final class DataModel { var common = 0 #if os(iOS) var iProp = 0 #endif } Xcode 15 beta 5 reports error: Cannot find type '_iProp' in scope Is platform specific property forbidden in Observable objects?
Replies
1
Boosts
0
Views
677
Activity
Jul ’23
Swift compiler crash in Xcode 15 beta 3 (15A5195k)
Somehow the Swift compiler is unable to this code: @Observable class ServiceBrowser: NSObject { typealias ResolveServiceCompletionBlock = (Bool, Error?) -> Void fileprivate var resolveServiceCompletionHandler: ResolveServiceCompletionBlock? = nil } Here's the crash: 4 . While evaluating request ASTLoweringRequest(Lowering AST to SIL for file "/Users/luc/Work/Repositories/app-shared/App/Shared/Connectivity/ServiceBrowser.swift") 5 . While silgen init accessor SIL function "@$s7App14ServiceBrowserC07resolveB17CompletionHandler33_5B15C352D9CC926D1F8A0ECAC5970199LLySb_s5Error_pSgtcSgvi". for init for resolveServiceCompletionHandler (at /Users/luc/Work/Repositories/ap-shared/App/Shared/Connectivity/ServiceBrowser.swift:86:21) 6 . While emitting reabstraction thunk in SIL function "@$sSbs5Error_pSgIegyg_ytIegd_TR".
Replies
2
Boosts
0
Views
1.3k
Activity
Jul ’23