Post

Replies

Boosts

Views

Activity

Reply to @State variable returns empty despite being set in .onAppear function
Here is a revised version of code: struct ContentView: View { @State var data: [Data2] @State var index: Int init() { index = 0 let filePath = Bundle.main.path(forResource: "data", ofType: "json") let url = URL(fileURLWithPath: filePath!) do { let data = try Data(contentsOf: url) let jsonDecoded = try JSONDecoder().decode([Data2].self, from: data) data = jsonDecoded return } catch let error as NSError { print("Fail: \(error.localizedDescription)") } catch { print("Fail: \(error)") } data = [] return } var body: some View { VStack { DataView(datum: data[index]) Spacer() SlideDots(current: $index) } }
Topic: Design SubTopic: General Tags:
Aug ’25
Reply to @State variable returns empty despite being set in .onAppear function
struct ContentView: View { @State var data: [Data2] @State var index: Int = 0 init() { let filePath = Bundle.main.path(forResource: "data", ofType: "json") let url = URL(fileURLWithPath: filePath!) // data = getData(url: url) // We cannot call getData in init do { let dataRead = try Data(contentsOf: url) let jsonDecoded = try JSONDecoder().decode([Data2].self, from: dataRead) data = jsonDecoded return } catch let error as NSError { print("Fail: \(error.localizedDescription)") } catch { print("Fail: \(error)") } data = [] return } var body: some View { VStack { DataView(data: data[index]) SlideDots(current: $index) } } } struct SlideDots: View { @Binding var current: Int var body: some View { HStack { if current > 0 { Spacer() .frame(width: 25) Button(action: { if current > 0 { current -= 1 }}) { Image(systemName: "chevron.left") } .foregroundStyle(getColor(type: .main)) .frame(width: 35) } else { Spacer() .frame(width: 60) } Spacer() ForEach(0..<4) { index in Spacer() .frame(width: 15) Circle() .fill(index == current ? Color.gray : Color.white) .stroke(Color.gray, lineWidth: 1) .frame(width: 15, height: 15) Spacer() .frame(width: 15) } Spacer() if current < 3 { Button(action: { if current < 3 { current += 1 }}) { Image(systemName: "chevron.right") } .foregroundStyle(getColor(type: .main)) .frame(width: 35) Spacer() .frame(width: 25) } else { Spacer() .frame(width: 60) } } } }
Topic: Design SubTopic: General Tags:
Aug ’25
Reply to @State variable returns empty despite being set in .onAppear function
I have a follow up question which you may have answered but I'm not sure. I am incrementing/decrementing a @State variable as a @Binding variable in another view: IndexView(current: $index) .onChange(of: index) { newValue in print("new value \(newValue)") } The variable newValue prints as it should (incrementing and decrementing) but the index variable doesn't seem to change. DataView(datum: data[index]) The DataView only displays data of index 0 despite the index incrementing.
Topic: Design SubTopic: General Tags:
Aug ’25
Reply to @State variable returns empty despite being set in .onAppear function
My apologies. The code below should compile. struct ContentView: View { @State var sampleData: [SampleData] @State var index: Int = 0 var body: some View { VStack { DataView(data: sampleData[index]) } .onAppear { print("on appear") let filePath = Bundle.main.path(forResource: "data", ofType: "json") let url = URL(fileURLWithPath: filePath!) sampleData = getData(url: url) print(sampleData) } } func getData(url: URL) -> [SampleData] { do { let data = try Data(contentsOf: url) let jsonDecoded = try JSONDecoder().decode([SampleData].self, from: data) return jsonDecoded } catch let error as NSError { print("Fail: \(error.localizedDescription)") } catch { print("Fail: \(error)") } print("test 1") return [SampleData(index: 0, str: "")] } }
Topic: Design SubTopic: General Tags:
Aug ’25
Reply to @State variable returns empty despite being set in .onAppear function
struct ContentView: View { @State var data: [Data] @State var index: Int = 0 var body: some View { VStack { DataView(data: features[index]) } .onAppear { print("on appear") let filePath = Bundle.main.path(forResource: "data", ofType: "json") let url = URL(fileURLWithPath: filePath!) data = getData(url: url) print(data) } } func getData(url: URL) -> [Data] { do { let data = try Data(contentsOf: url) let jsonDecoded = try JSONDecoder().decode([Data].self, from: data) return jsonDecoded } catch let error as NSError { print("Fail: \(error.localizedDescription)") } catch { print("Fail: \(error)") } print("test 1") return [Data(index: 0, str: "")] } } struct Data: Decodable, Hashable { let index: Int let str: String } [ { "index": 0, "str": "String 1" }, { "index": 1, "str": "String 2" } ]
Topic: Design SubTopic: General Tags:
Aug ’25
Reply to Background App Refresh
With the following configuration, start(), handleAppRefresh(), and updateNow() doesn't run. The only thing that is different with my implementation that I have noticed is that I passed true to setTaskCompleted instead of success because I was getting an error. App: struct Peace_of_MindApp: App { var backgroundRefreshModel: BackgroundRefreshModel = { let result = BackgroundRefreshModel() result.start() return result }() var body: some Scene { WindowGroup { ContentView(backgroundRefreshModel: backgroundRefreshModel) } } } ContentView: struct ContentView: View { let backgroundRefreshModel: BackgroundRefreshModel var body: some View { ZStack { } .onAppear { backgroundRefreshModel.scheduleAppRefresh() } } BackgroundRefreshModel: @Observable @MainActor final class BackgroundRefreshModel { let routineResetID = "app.Task" private var isAppRefreshScheduled: Bool = false private(set) var lastUpdate: Date? = nil private var isUpdating: Bool = false let log = Logger(subsystem: "app.Task", category: "refresh") func updateNow() async { do { if self.isUpdating { return } self.isUpdating = true defer { self.isUpdating = false } try await Task.sleep(for: .seconds(3)) self.lastUpdate = .now } catch { // discard errors } } func start() { BGTaskScheduler.shared.register(forTaskWithIdentifier: routineResetID, using: .main) { task in let appRefreshTask = task as! BGAppRefreshTask self.handleAppRefresh(appRefreshTask: appRefreshTask) } } private func handleAppRefresh(appRefreshTask: BGAppRefreshTask) { self.isAppRefreshScheduled = false let swiftTask = Task { let success = await self.updateNow() appRefreshTask.setTaskCompleted(success: true) appRefreshTask.expirationHandler = nil } appRefreshTask.expirationHandler = { swiftTask.cancel() } } func scheduleAppRefresh() { if self.isAppRefreshScheduled { self.log.debug("will not schedule, already scheduled") return } self.isAppRefreshScheduled = true do { self.log.debug("will schedule, task: \(self.routineResetID, privacy: .public)") let request = BGAppRefreshTaskRequest( identifier: routineResetID ) request.earliestBeginDate = Date(timeIntervalSinceNow: 10) try BGTaskScheduler.shared.submit(request) } catch { // discard errors } } }
Jul ’25
Reply to Background App Refresh
With that implementation the BGTaskScheduler function does not run within the start() function despite result.start() being called in the App struct. "will schedule, task: app.Task" in scheduleAppRefresh prints in the console, and I also have print(request) that prints this: <BGAppRefreshTaskRequest: app.TaskDate: 2025-07-24 18:30:14 +0000> Also, just to clarify, what function is the background task itself supposed to be in?
Jul ’25
Reply to Background App Refresh
Thank you for the explanation. I am getting two errors: Unless I pass task to handleAppRefresh as shown below I get an error as nothing is being passed to it: self.handleAppRefresh(appRefreshTask: task as! BGAppRefreshTask) And an error with this line as well: appRefreshTask.setTaskCompleted(success: success) "Cannot convert value of type '()' to expected argument type 'Bool'
Jul ’25
Reply to Background App Refresh
Just following up as I still don't quite understand. Does RefreshAppContentsOperation run automatically in the background at the designated time if the task is BGTaskScheduler.shared.register() and BGTaskScheduler.shared.submit() ran, or is that why there is operationQueue? If I were to not use operationQueue what would be the alternative? class BackgroundTasksController: ObservableObject { func scheduleTask() { BGTaskScheduler.shared.register(forTaskWithIdentifier: "app.Task", using: nil) { task in Task { await self.handleAppRefresh(task: task as! BGAppRefreshTask) } } } private func handleAppRefresh(task: BGAppRefreshTask) async { Task { scheduleAppRefresh() RefreshAppContentsOperation() } } func scheduleAppRefresh() { let request = BGAppRefreshTaskRequest(identifier: "app.Task") request.earliestBeginDate = Date(timeIntervalSinceNow: 60) do { try BGTaskScheduler.shared.submit(request) } catch { print("Could not schedule app refresh: \(error)") } } } final class RefreshAppContentsOperation: Operation, @unchecked Sendable { }
Jul ’25
Reply to Background App Refresh
I am getting the following error using the breakpoints below. I'm not sure if that indicates anything. It doesn't appear that RefreshAppContentsOperation runs. App.debug.dylib`partial apply for closure #1 in View.function(): -> 0x103aade10 <+0>: orr x29, x29, #0x1000000000000000 0x103aade14 <+4>: sub sp, sp, #0x20 0x103aade18 <+8>: stp x29, x30, [sp, #0x10] 0x103aade1c <+12>: str x22, [sp, #0x8] 0x103aade20 <+16>: add x29, sp, #0x10 0x103aade24 <+20>: ldr x9, [x22] 0x103aade28 <+24>: str x9, [sp] 0x103aade2c <+28>: mov x8, x29 0x103aade30 <+32>: sub x8, x8, #0x8 0x103aade34 <+36>: str x9, [x8] 0x103aade38 <+40>: ldr x0, [x9, #0x18] 0x103aade3c <+44>: ldr x8, [x22] 0x103aade40 <+48>: mov x10, x29 0x103aade44 <+52>: sub x10, x10, #0x8 0x103aade48 <+56>: str x8, [x10] 0x103aade4c <+60>: str x8, [x9, #0x10] 0x103aade50 <+64>: bl 0x103ad626c ; symbol stub for: swift_task_dealloc 0x103aade54 <+68>: ldr x8, [sp] 0x103aade58 <+72>: ldr x22, [x8, #0x10] 0x103aade5c <+76>: ldr x0, [x22, #0x8] 0x103aade60 <+80>: ldp x29, x30, [sp, #0x10] 0x103aade64 <+84>: and x29, x29, #0xefffffffffffffff 0x103aade68 <+88>: add sp, sp, #0x20 0x103aade6c <+92>: br x0 private func handleAppRefresh(task: BGAppRefreshTask) async { Task { let queue = OperationQueue() scheduleAppRefresh() // breakpoint print("test") // breakpoint // Create an operation that performs the main part of the background task. let operation = RefreshAppContentsOperation() // breakpoint // Provide the background task with an expiration handler that cancels the operation. task.expirationHandler = { operation.cancel() } // Inform the system that the background task is complete // when the operation completes. operation.completionBlock = { task.setTaskCompleted(success: !operation.isCancelled) } // Start the operation. queue.addOperation(operation) // breakpoint } } // Schedule a new refresh task. func scheduleAppRefresh() { let request = BGAppRefreshTaskRequest(identifier: "app.BackgroundTask") // Fetch no earlier than 15 minutes from now. request.earliestBeginDate = Date(timeIntervalSinceNow: 60) print(request) // breakpoint do { try BGTaskScheduler.shared.submit(request) } catch { print("Could not schedule app refresh: \(error)") } }
Jul ’25
Reply to Background App Refresh
The app no longer crashes, but with my current configuration, the task does not run. I initialize the task scheduler in the App file's init() function, which calls handleAppRefresh(), which calls RefreshAppContentsOperation()At a given time I call scheduleAppRefresh(), which I thought would preform the task at the scheduled time. The function runs and prints this: <BGAppRefreshTaskRequest: app.Task, earliestBeginDate: 2025-07-01 21:38:43 +0000> All of these functions referenced are in my post above. I tried implementing a queue by doing this: let queue = OperationQueue() let operation = RefreshAppContentsOperation() queue.addOperation(operation) How can I resolve this by Queue or .task?
Jul ’25
Reply to Testing In-App Purchases
The SubscriptionsHandler class I have is observable and configured just like the documentation you provided so I'm not sure why I'm getting the error. Also, In the View, the SubscriptionsHandler class is called as an environment variable but is never used. Why is that?
Topic: Design SubTopic: General Tags:
Jun ’25