Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftData make my app very slow
Hello, I have been working on SwiftData since a month now and i found very weird that every time i update a data inside a SwiftData model my app became very slow. I used the instrument if something was wrong, and i see memory increasing without releasing. My app have a list with check and unchecked elements (screeshot below). I just press check and unchecked 15 times and my memory start from 149mb to 361mb (screenshots below). For the code i have this model. final class Milestone: Identifiable { // ********************************************************************* // MARK: - Properties @Transient var id = UUID() @Attribute(.unique) var uuid: UUID var text: String var goalId: UUID var isFinish: Bool var createdAt: Date var updatedAt: Date var goal: Goal? init(from todoTaskResponse: TodoTaskResponse) { self.uuid = todoTaskResponse.id self.text = todoTaskResponse.text self.goalId = todoTaskResponse.goalId self.isFinish = todoTaskResponse.isFinish self.createdAt = todoTaskResponse.createdAt self.updatedAt = todoTaskResponse.updatedAt } init(uuid: UUID, text: String, goalId: UUID, isFinish: Bool, createdAt: Date, updatedAt: Date, goal: Goal? = nil) { self.uuid = uuid self.text = text self.goalId = goalId self.isFinish = isFinish self.createdAt = createdAt self.updatedAt = updatedAt self.goal = goal } } For the list i have var milestonesView: some View { ForEach(milestones) { milestone in MilestoneRowView(task: milestone) { milestone.isFinish.toggle() } .listRowBackground(Color.backgroundComponent) } .onDelete(perform: deleteMilestone) } And this is the cell struct MilestoneRowView: View { // ********************************************************************* // MARK: - Properties var task: Milestone var action: () -> Void init(task: Milestone, action: @escaping () -> Void) { self.task = task self.action = action } var body: some View { Button { action() } label: { HStack(alignment: .center, spacing: 8) { Image(systemName: task.isFinish ? "checkmark.circle.fill" : "circle") .font(.title2) .padding(3) .contentShape(.rect) .foregroundStyle(task.isFinish ? .gray : .primary) .contentTransition(.symbolEffect(.replace)) Text(task.text) .strikethrough(task.isFinish) .foregroundStyle(task.isFinish ? .gray : .primary) } .foregroundStyle(Color.backgroundComponent) } .animation(.snappy, value: task.isFinish) } } Does someone have a idea? Thanks
1
0
424
Apr ’24
NaviagationStack, List View and NavigatioinLink dynamic rows
When I run Simulator on my iPhone 15 and iPhone device, the dynamic list of NavigationLink rows is created as expected. However, when I run the same code on my iPhone device, the dynamic list of NavigationLink rows is not made. My code snippet: List { ForEach(searchResults, id: .self) { name in NavigationLink { Text(name) Button(action: { print("Button Clicked!") dynamicObjectsHandler(thisObjectName: name) }) { Text("Toggle Object \(searchText)") .navigationTitle("Dynamic Guiding Objects") } } label: { Text(name) } } } Additional information: iOS version: 17.6 iPhone 14 Pro iOS Deployment Target 17.5 Xcode version 15.4
0
0
89
2w
Inconsistency on view lifecycle events between UIKit and SwiftUI when using UIVPageViewController
Overview I've found inconsistency on view lifecycle events between UIKit and SwiftUI as the following shows when using UIVPageViewController and UIHostingController as one of its pages. SwiftUI View onAppear is only called at the first time to display and never called in the other cases. UIViewController viewDidAppear is not called at the first time to display, but it's called when the page view controller changes its page displayed. The whole view structure is as follows: UIViewController (root) UIPageViewController (as its container view) UIHostingController (as its page) SwiftUI View (as its content view) UIViewControllerRepresentable (as a part of its body) UIViewController (as its content) Environment Xcode Version 15.4 (15F31d) iPhone 15 Pro (iOS 17.5) (Simulator) iPhone 8 (iOS 15.0) (Simulator) Sample code import UIKit import SwiftUI class ViewController: UIViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource { private var pageViewController: UIPageViewController! private var viewControllers: [UIViewController] = [] override func viewDidLoad() { super.viewDidLoad() setup() } private func setup() { pageViewController.delegate = self pageViewController.dataSource = self let page1 = UIHostingController(rootView: MainPageView()) let page2 = UIViewController() page2.view.backgroundColor = .systemBlue let page3 = UIViewController() page3.view.backgroundColor = .systemGreen viewControllers = [page1, page2, page3] pageViewController.setViewControllers([page1], direction: .forward, animated: false) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) guard let pageViewController = segue.destination as? UIPageViewController else { return } self.pageViewController = pageViewController } func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { print("debug: \(#function)") } func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { print("debug: \(#function)") guard let viewControllerIndex = viewControllers.firstIndex(of: viewController) else { return nil } let previousIndex = viewControllerIndex - 1 guard previousIndex >= 0, viewControllers.count > previousIndex else { return nil } return viewControllers[previousIndex] } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { print("debug: \(#function)") guard let viewControllerIndex = viewControllers.firstIndex(of: viewController) else { return nil } let nextIndex = viewControllerIndex + 1 guard viewControllers.count != nextIndex, viewControllers.count > nextIndex else { return nil } return viewControllers[nextIndex] } } struct MainPageView: View { var body: some View { VStack(spacing: 0) { PageContentView() PageFooterView() } .onAppear { print("debug: \(type(of: Self.self)) onAppear") } .onDisappear { print("debug: \(type(of: Self.self)) onDisappear") } } } struct PageFooterView: View { var body: some View { Text("PageFooterView") .padding() .frame(maxWidth: .infinity) .background(Color.blue) .onAppear { print("debug: \(type(of: Self.self)) onAppear") } .onDisappear { print("debug: \(type(of: Self.self)) onDisappear") } } } struct PageContentView: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> some UIViewController { PageContentViewController() } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} } class PageContentViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setup() } private func setup() { view.backgroundColor = .systemYellow let label = UILabel() label.text = "PageContentViewController" label.font = .preferredFont(forTextStyle: .title1) view.addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ label.centerXAnchor.constraint(equalTo: view.centerXAnchor), label.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) print("debug: \(type(of: Self.self)) \(#function)") } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) print("debug: \(type(of: Self.self)) \(#function)") } } Logs // Display the views debug: MainPageView.Type onAppear debug: PageFooterView.Type onAppear // Swipe to the next page debug: pageViewController(_:viewControllerAfter:) debug: pageViewController(_:viewControllerBefore:) debug: PageContentViewController.Type viewDidDisappear(_:) debug: pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) debug: pageViewController(_:viewControllerAfter:) // Swipe to the previous page debug: PageContentViewController.Type viewDidAppear(_:) debug: pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:) debug: pageViewController(_:viewControllerBefore:) As you can see here, onAppear is only called at the first time to display but never called in the other cases while viewDidAppear is the other way around.
0
0
132
2w
NO ANIMATIONS in NavigationStack or NavigationSplitView
I'm building a macOS app using SwiftUI and I recently updated to xcode 14.3. Since then I've been debugging why none of my animations were working, it turned out that the NavigationSplitView or NavigationStack are somehow interfering with all the animations from withAnimation to .transition() and everything in between. Is anyone else experiencing this, knows a work around or knows why this is happening?
9
8
5.4k
Apr ’23
SF Symbol image color in the menu bar
I can set color of the SF symbol image in the application window but cannot do the same in the menu bar. I wonder how I can change the color in the menu? import SwiftUI @main struct ipmenuApp: App { var body: some Scene { MenuBarExtra { Image(systemName: "bookmark.circle.fill") .renderingMode(.original) .foregroundStyle(.red) } label: { Image(systemName: "bookmark.circle.fill") .renderingMode(.original) .foregroundStyle(.red) } } } xcodebuild -version Xcode 15.0 Build version 15A240d
4
1
761
Oct ’23
Draggable Views with Child Drop Destination Elements not Draggable in iOS 18
I'm creating an app that has a number of draggable views, and each of these views themselves contain child dropDestination views. In iOS 17.x they are draggable as expected. However, in iOS 18 betas 1 & 2 a long press on these views does NOT pick them up (start the drag operation). I have not tested with macOS 15 betas but the issue may well exist there also. Is this a bug in iOS 18 betas 1 & 2 or does the implementation need to be updated somehow for iOS 18? Please see example code below: Views: import SwiftUI extension View { func dropTarget<T>(for payloadType: T.Type, withTitle title: String) -> some View where T: Transferable { modifier(DropTargetViewModifer<T>(title: title)) } } struct DropTargetViewModifer<T>: ViewModifier where T: Transferable { let title: String func body(content: Content) -> some View { content .dropDestination(for: T.self) { items, location in print("Item(s) dropped in \(title)") return true } isTargeted: { targted in if targted { print("\(title) targeted") } } } } struct InnerTestView: View { let title: String let borderColor: Color var body: some View { ZStack { Text(title) .padding() Rectangle() .stroke(borderColor) } .contentShape(Rectangle()) } } struct TestView: View { var body: some View { VStack(spacing: 0.0) { HStack(alignment: .top, spacing: 0.0) { InnerTestView(title: "Drop Zone 1", borderColor: .pink) .dropTarget(for: ItemType1.self, withTitle: "Drop Zone 1") InnerTestView(title: "Drop Zone 2", borderColor: .indigo) .dropTarget(for: ItemType2.self, withTitle: "Drop Zone 2") } InnerTestView(title: "Drop Zone 3", borderColor: .orange) .dropTarget(for: ItemType3.self, withTitle: "Drop Zone 3") } .contentShape(Rectangle()) .draggable(ItemType1(id: "Object 1")) } } struct ContentView: View { var body: some View { ScrollView { LazyVStack { TestView() TestView() InnerTestView(title: "Draggable 2", borderColor: .orange) .draggable(ItemType2(id: "Object 2")) InnerTestView(title: "Draggable 3", borderColor: .indigo) .draggable(ItemType3(id: "Object 3")) } .padding() } } } Transfer Representations: import UniformTypeIdentifiers import CoreTransferable extension UTType { static let itemType1 = UTType(exportedAs: "com.droptest.typeone") static let itemType2 = UTType(exportedAs: "com.droptest.typetwo") static let itemType3 = UTType(exportedAs: "com.droptest.typethree") } struct ItemType1: Codable, Transferable { var id: String public static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .itemType1) } } struct ItemType2: Codable, Transferable { var id: String public static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .itemType2) } } struct ItemType3: Codable, Transferable { var id: String public static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .itemType3) } }
3
1
192
2w
CloudKit Stopped Syncing after adding new Entities
Can someone please shed some light? I have an app that uses Core Data and CloudKit, up until the last version, I was able to sync data between devices but now after I added two new Entities for some reason it stopped syncing between devices. Here is how I did the change: Created a new Core Data container. Added the new Entities and their Attributes Tested the new Entities locally to be able to send the new schema to CloudKit. Went to CloudKit and made sure that the new Entities and Attributes were reflected on the Developent database. Deploy Schema Cahnges. Went to the Production database to make sure the new schema was deployed; and it was, both databases look the same. Testing: Tested in the simulator and with a real device and everything syncs, even the new Entities. If I download the app from the App Store on two different devices they do NOT sync. Based on the procedure I'm describing above, is there any important step I may have missed when doing the migration? I'm not sure if this is related to the syncing issue but after testing a few times, I no longer can turn the iCloud on, I get the following message when I try to turn iCloud Sync On. CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate resetAfterError:andKeepContainer:]: <NSCloudKitMirroringDelegate: 0x282c488c0> - resetting internal state after error: Error Domain=NSCocoaErrorDomain Code=134410 "CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process." UserInfo={NSURL=file:///var/mobile/Containers/Data/Application/73F19BC7-4538-4098-85C7-484B36192CF3/Library/Application%20Support/CoreDataContainer.sqlite, NSLocalizedFailureReason=CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process., NSUnderlyingException=Illegal attempt to register a second handler for activity identifier com.apple.coredata.cloudkit.activity.setup.8D4C04F6-8040-445A-9447-E5646484521} Any idea of what could be wrong and preventing the devices from syncing? Any idea or suggestion is welcome. Thanks
3
0
1.8k
May ’23
Question About Weak Self Usage
Hello everyone. I have a small question about Weak Self. In the example below, I am doing a long process to the data I query with SwiftData. (For this reason, I do it in the background.) I don't know if there is a possibility of a memory leak when the view is closed because this process takes a long time. import SwiftUI import SwiftData struct ActiveRegView: View { @Query(filter: #Predicate<Registration> { $0.activeRegistration }, animation: .default) private var regs: [Registration] @Environment(ViewModel.self) private var vm @State private var totalParkingFee: Decimal = 0 var body: some View { ... .onAppear { var totalParkingFee = Decimal() DispatchQueue.global(qos: .userInitiated).async { for reg in regs { totalParkingFee += vm.parkingFee(from: reg.entryRegistration.entryDate, to: .now, category: reg.category, isCustomPrice: reg.isCustomPrice) } DispatchQueue.main.async { withAnimation { totalParkingFee = totalParkingFee } } } } } } I use ViewModel with @Environment, so I don't initilize ViewModel every time view is initilized. I know it's a simple question and I thank you in advance for your answers.
0
0
112
2w
PKCanvasView working on preview, but not on simulator or app
Hey, so I am working on a note taking part of my app and I have been working on allowing different inputs. I got the PKCanvas to work on the preview and on the simulator when it is the only thing on the window group. But when I use this View as part of the tool selection in my app, when the user selects the Canvas view it loads but scribbles don't work, only in the preview in Xcode. I don't know why this behavior is happening. The flow in which the PKCanvasView appears is, user taps NavLink to see their notes, in the NotesView they tap to show the toolbar, toolbar has 4 types of input, text, images, audio, scribbles (all other inputs work accordingly), user taps scribbles the view loads correctly but doesn't allow them to draw. I have set the drawingPolicy to anyInput
0
0
110
2w
onMove
Im new to swiftui and I just tried implementing onMove into my project but for some reason it not only lags a lot when I attempt to move the item but the item then goes back to its original place any idea why?(Also my ItemModel does conform to Identifiable so it does have an id) import SwiftUI struct ListView: View { @State private var itemModel : [ItemModel] = [ ItemModel(title: "This Is Item 1", isCompleted: false), ItemModel(title: "This Is Item 2", isCompleted: true), ItemModel(title: "This Is Item 3", isCompleted: false) ] var body: some View { VStack(spacing: 20) { List{ ForEach(itemModel) { items in Text(items.title) } .onDelete(perform: { indexSet in itemModel.remove(atOffsets: indexSet) }) .onMove(perform: { indices, newOffset in itemModel.move(fromOffsets: indices, toOffset: newOffset) }) } .listStyle(.plain) .toolbar { ToolbarItem(placement: .topBarLeading){ EditButton() } ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: AddItemsView(), label: { Text("add") }) } } Spacer() } .navigationTitle("To Do List ✏️") } }
1
0
75
2w
SwiftUI Crashes only on A-Chip device
Hey there, I am currently developing a SwiftUI app for iPad. However, I am currently experiencing a behavior, that I can not explain. My code creates a user-management view. This all works fine if I run it on my iPad Pro with Apple-M-Chip. However, if I try to run the exact same code on an older A-Chip iPad Air (4th Generation), my app crashes. I can recreate this behavior in the simulator on my Mac. When I run it on an iPad Pro Simulator, all works fine. When I run it in an iPad Air (4th Gen) simulator, the app becomes unresponsive. Unfortunatley Xcode does not throw any error that I could use to identify the problem. Currently I solved it with a work-around: As soon as I add a Spacer (even with a with of 0) the code works as expected and the UI is shown. As soon as I remove the Spacer, it crashes again. HStack(alignment: .top){ VStack{ if(data.ui_user.id != -1){ HStack{ Text("Employee-No.:") Spacer() TextField("Employee-No.", value: $data.ui_user.id, format: .number).textFieldStyle(.roundedBorder).disabled(true).containerRelativeFrame(.horizontal, count: 10, span: 3, spacing: 0) } } HStack{ Text("Family Name:") Spacer() TextField("Family Name", text: $data.ui_user.familyName).textFieldStyle(.roundedBorder).containerRelativeFrame(.horizontal, count: 10, span: 3, spacing: 0) } HStack{ Text("Given Name:") Spacer() TextField("Given Name", text: $data.ui_user.givenName).textFieldStyle(.roundedBorder).containerRelativeFrame(.horizontal, count: 10, span: 3, spacing: 0) } HStack{ Text("Role:") Spacer() Picker("Select role", selection: $data.selectedRole){ ForEach(0 ..< self.availableRoles.count, id:\.self){ Text(self.availableRoles[$0].name ?? "???").tag($0) } }.pickerStyle(.menu).containerRelativeFrame(.horizontal, count: 10, span: 3, spacing: 0).background(.drkBlueContainer).cornerRadius(5).foregroundColor(.drkOnBlueContainer).tint(.drkOnBlueContainer) //If I add this spacer, it works. If not, it crashes //Spacer().frame(width: 0.0) }.disabled(noEditAdmin && data.ui_user.id != -1) } Divider() VStack{ HStack{ Text("Created at:") Spacer() TextField("Created at", value: $data.ui_user.createdAt, format: .dateTime).textFieldStyle(.roundedBorder).disabled(true).containerRelativeFrame(.horizontal, count: 10, span: 3, spacing: 0) } HStack{ Toggle("Terminates:", isOn: $data.ui_user.expires) .padding(.trailing, 2.0) } if(data.ui_user.expires){ HStack{ DatePicker("Terminates at:", selection: $data.ui_user.expiresAt, displayedComponents: .date).pickerStyle(.automatic) }} } } If anyone has any ideas, I would be very grateful for a hint :-)
2
0
158
Jun ’24
My loop makes a click noise each time it starts
The loop plays smoothly in audacity but when I run it in the device or simulator it clicks each loop at different intensities. I config the session at App level: let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers]) try audioSession.setActive(true) } catch { print("Setting category session for AVAudioSession Failed") } And then I made my method on my class: func playSound(soundId: Int) { let sound = ModelData.shared.sounds[soundId] if let bundle = Bundle.main.path(forResource: sound.filename, ofType: "flac") { let backgroundMusic = NSURL(fileURLWithPath: bundle) do { audioPlayer = try AVAudioPlayer(contentsOf:backgroundMusic as URL) audioPlayer?.prepareToPlay() audioPlayer?.numberOfLoops = -1 // for infinite times audioPlayer?.play() isPlayingSounds = true } catch { print(error) } } } Does anyone have any clue? Thanks! PS: If I use AVQueuePlayer and repeat the item the click noise disappear (but its no use, because I would need to repeat it indefinitely without wasting memory), if I use AVLooper I get a silence between loops. All with the same sound. Idk :/ PS2: The same happens with ALAC files.
4
2
808
Jul ’23
List Rows Can Be Moved While Not Editing
Hi, I am building a view containing a list of struct objects. I have implemented the onMove to allow the list rows to be moved together with the toolbar EditButton. This works but I have a problem as per title, even when the EditButton is not clicked, i.e., not in editing mode, I still can move the list rows by long pressing the rows. I have searched high and low for a solution but couldn't find one that works perfectly. Below is the code snippet. I am a new iOS dev and really appreciate if someone could help me. Many thanks! @AppStorage("fruits") private var fruits = Fruits.fruits var body: some View { NavigationStack { VStack { List { ForEach(fruits) { fruit in NavigationLink(destination: FruitsView(title: fruit.title)) { fruit.icon Text(fruit.title) } } .onMove { fruits.move(fromOffsets: $0, toOffset: $1) } } .environment(\.defaultMinListRowHeight, UIElementConstants.listCellHeight) } .toolbar { EditButton() } .navigationTitle("Fruits") } } struct Fruits: Identifiable, Codable { var id: UUID var title: String var iconName: String var icon: Image { Image(systemName: self.iconName) } init(id: UUID = UUID(), title: String, iconName: String) { self.id = id self.title = title self.iconName = iconName } } extension Fruits { static let fruits: [Fruits] = [ Fruits( title: "Apple", iconName: "basket.fill"), Fruits( title: "Banana", iconName: "basket.fill"), Fruits( title: "Pineapple", iconName: "basket.fill") ] }
4
1
213
3w
Using availablity checks with new .defaultWindowPlacement API
How can I use availability checks with the new defaultWindowPlacement API so I can ensure visionOS 2 users get the correct window placement and visionOS 1 users fall back to the old window placement mechanism? I have tried using if #available and @available in different ways, but end up with either an error that says control flow statements aren't allowed in SceneBuilders or that the return type of the two branches of my control flow statement do not match if I omit the SceneBuilder property. An example of how to use .defaultWindowPlacement with visionOS 1 support would be nice. Thank you!
1
0
209
3w
iOS app running in compatibility mode on Apple Vision Pro does not apply hoverEffect to SwiftUI View
We tested our iOS app on visionOS and found that the hover effect works on most of UIKit views, but it does not work on most of SwiftUI views. SwiftUI views are used within UIHostingController. I created a new project (Storyboard based iOS app) and displayed the following SwiftUI view in UIHostingController and found that the buttons in the List were highlighted, but not the standalone buttons. struct SwiftUIView: View { var body: some View { List { // This button has the hover effect. Button { print("Hello") } label: { Text("Hello") } } // This button does't have the hover effect. Button { print("Hello") } label: { Text("Hello") } .hoverEffect() } } Is there a way to highlight any SwiftUI view?
2
1
328
Jun ’24
SwiftUI, REST, and websockets
I'm coming back to iOS development after years away and diving head-first into SwiftUI. It's a lot of fun, but I've hit a brick wall. The scenario is I have a main view (which itself is a tabview, not important other than that it's not the top-level of the view hierarchy). This has subviews that rely on data coming back from a REST call to the cloud, but then some subviews need to turn around and make subsequent network calls to set up websockets for realtime updates. In the main view's .onAppear, I fire off an async REST call, it returns JSON that gets parsed into a ModelView. The ViewModel is declared in the top view like this: class ViewModel: ObservableObject { @Published var appData = CurrentREST() // Codables from JSON @State var dataIsLoaded : Bool = false func fetchData() async { await _ = WebService().downloadData(fromURL: "current") { currentData in DispatchQueue.main.async { self.appData = currentData self.dataIsLoaded = true } } } } The main view declares the model view: struct HomeTabView: View { @ObservedObject var viewModel = ViewModel() @Binding private var dataReceived: Bool ... } In the toplevel view, the REST call is triggered like this: .onAppear { if !viewModel.dataIsLoaded { Task { await viewModel.fetchData() DispatchQueue.main.async { self.dataReceived = true } } } } The viewModel gets passed down to subviews so they can update themselves with the returned data. That part all works fine. But it's the next step that break down. A subview needs to go back to the server and set up subscriptions to websockets, so it can do realtime updates from then on. It's this second step that is failing. The dataReceived binding is set to true when the REST call has completed. The viewModel and dataReceived flags are passed down to the subviews: SummaryView(viewModel: viewModel, dataIsLoaded: self.dataReceived) What needs to happen next is inside the subview to call a function to wire up the next websocket steps. I've tried setting up: struct SummaryView: View { @ObservedObject var viewModel: ViewModel @State var dataIsLoaded: Bool = false ... }.onChange(of: dataIsLoaded) { setupWebSocket() } Problem is, the onChange never gets called. I've tried various permutations of setting up a @State and a @Binding on the view model, and a separate @State on the main view. None of them get called and the subview's function that wires up the websockets never gets called. The basic question is: How do you trigger a cascading series of events through SwiftUI so external events (a network call) can cascade down to subviews and from there, their own series of events to do certain things. I haven't gone deep into Combine yet, so if that's the solution, I'll go there. But I thought I'd ask and see if there was a simpler solution. Any suggestions or pointers to best practices/code are most appreciated.
3
0
206
3w