Post

Replies

Boosts

Views

Activity

Reply to WidgetKit with Data from CoreData
A solution is not to rely on a Data Manager class and its associates but to use UserDefaults so that Widget's getTimeline method will be called when ContentView submits data to it. By this approach, you can update Widget's View. import SwiftUI import WidgetKit struct ContentView: View { var body: some View { VStack { Button { let task0 = TaskItem(id: UUID(), name: "Dish washing", isComplete: false, dueDate: Date.now.addingTimeInterval(86400)) let task1 = TaskItem(id: UUID(), name: "Bed making", isComplete: false, dueDate: Date.now.addingTimeInterval(86400 * 2)) saveTasksToWidget(tasks: [task0, task1]) } label: { Image(systemName: "globe") .imageScale(.large) } .tint(.pink) .buttonStyle(.borderedProminent) } .padding() } private func saveTasksToWidget(tasks: [TaskItem]) { guard let sharedDefaults = UserDefaults(suiteName: "group.abc") else { print("Failed to get shared UserDefaults.") return } do { let encoder = JSONEncoder() let encodedData = try encoder.encode(tasks) sharedDefaults.set(encodedData, forKey: "widgetTasksArray") WidgetCenter.shared.reloadAllTimelines() } catch { print("Error encoding tasks: \(error)") } } } // TaskItem.swift // import Foundation struct TaskItem: Codable, Identifiable { let id: UUID let name: String let isComplete: Bool let dueDate: Date static let previewTasks = [ TaskItem(id: UUID(), name: "Rose", isComplete: false, dueDate: Date.now.addingTimeInterval(86400)), TaskItem(id: UUID(), name: "Chrisanthumum", isComplete: true, dueDate: Date.now.addingTimeInterval(86400 * 2)), TaskItem(id: UUID(), name: "Garden Dahlia", isComplete: false, dueDate: Date.now.addingTimeInterval(86400 * 3)) ] } // CrazyWidget.swift // import WidgetKit import SwiftUI struct SimpleEntry: TimelineEntry { let date: Date let tasks: [TaskItem] } struct Provider: TimelineProvider { let appGroupID = "group.abc" let dataKey = "widgetTasksArray" func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), tasks: TaskItem.previewTasks) } func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { let currentTasks = loadTasks() let entry = SimpleEntry(date: Date(), tasks: currentTasks) completion(entry) } func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let currentTasks = loadTasks() let entry = SimpleEntry(date: Date(), tasks: currentTasks) let nextUpdate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())! let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) completion(timeline) } private func loadTasks() -> [TaskItem] { var taskItems: [TaskItem] = [] if let sharedDefaults = UserDefaults(suiteName: appGroupID), let savedData = sharedDefaults.data(forKey: dataKey) { do { let decoder = JSONDecoder() taskItems = try decoder.decode([TaskItem].self, from: savedData) } catch { print("Error decoding tasks from App Group: \(error)") taskItems = TaskItem.previewTasks // Fallback on decoding failure } } else { taskItems = TaskItem.previewTasks // Fallback on access failure } return taskItems } } struct CrazyWidgetEntryView : View { var entry: Provider.Entry var body: some View { VStack(alignment: .leading) { Text("Pending Tasks") .font(.headline) .foregroundColor(.blue) Divider() if entry.tasks.isEmpty { Text("All clear! No tasks found.") .font(.caption) .foregroundColor(.secondary) } else { VStack(alignment: .leading, spacing: 4) { ForEach(entry.tasks.prefix(3)) { task in HStack { Image(systemName: task.isComplete ? "checkmark.circle.fill" : "circle") .foregroundColor(task.isComplete ? .green : .orange) Text(task.name) .font(.caption) .strikethrough(task.isComplete) .lineLimit(1) } } } } } .padding() } } struct CrazyWidget: Widget { let kind: String = "RailMe" var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider()) { entry in CrazyWidgetEntryView(entry: entry) } .configurationDisplayName("RailMe GGGGG") .description("View your current tasks saved from the main app.") .supportedFamilies([.systemSmall, .systemMedium]) } } #Preview("Small - Full Data") { CrazyWidgetEntryView(entry: SimpleEntry(date: Date(), tasks: TaskItem.previewTasks)) }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
2w
Reply to how to navigate programmatically without navigation link?
Use navigationDestination(isPresented:destination:) and hide the Back button at the destination View? import SwiftUI struct ContentView: View { @State var goToHello = false var body: some View { NavigationStack { Button { goToHello = true } label: { Text("Go to Hello?") } .navigationDestination(isPresented: $goToHello) { HelloView() } } } } #Preview { ContentView() } struct HelloView: View { var body: some View { NavigationStack { VStack { Text("Hello!") } .navigationBarBackButtonHidden() } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
3w
Reply to 32 byte NSNumber memory leak - how to fix?
Have you asked Gemini or ChatGPT about this case? When it comes to Swift Concurrency, they are quite good at it. Concerning your issue, Gemini reports to me several issues with the following last comment. In summary, the most critical issue is the unreliable view hierarchy traversal using view.superview?.superview. You should refactor the ViewExtractor to reliably pass the host UIView back to the modifier.
Topic: UI Frameworks SubTopic: UIKit Tags:
3w
Reply to Unable to test first In-App Purchase for non-consumable - receive empty array.
When you have a submit-ready IAP, a new section will appear right below the Build section and above the Game Center checkbox. If you don't click on 'Select In-App Purchases or Subscriptions' to include your IAP, that will be it. The cruise ship has already sailed out. If that's the case, you have to start over and submit a software update to go with a new IAP product identifier.
Nov ’25
Reply to Guideline 3.1.2 - Business - Payments - Subscriptions
State the EULA URL for your app in the description of your app. Indicate what a subscription plan enables the user to do upon purchase. Indicate what benefits are. Indicate what happens to the app after a subscription plan expires. Indicate how they can request a refund. Indicate how they can check out when their subscription plan expires. Indicate how they can cancel their auto-renewal subscription.
Nov ’25
Reply to System Data Occupying Half of My Storage
If you develop software in SwiftUI, you should know better. Every time you initiate an Xcode project, a new folder with a ton of data is created inside the DerivedData folder. If you duplicate an existing Xcode project, a duplicate after the Xcode project name will be created in the DrivedData folder. I occasionally go to the DerivedData folder and delete the folders that I no longer keep track of although my Mac mini gives me 512 GB of space.
Oct ’25
Reply to How to change the copyright of my app
What exactly is the thing that you refer to as Copyright? Are you talking about the Copyright reference of the software title at App Store Connect as shown below? If so, wouldn't it just be the matter of the new guy submitting a new software update so that he or she could edit it?
Topic: Community SubTopic: Apple Developers Tags:
Oct ’25