Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics

Post

Replies

Boosts

Views

Activity

refreshed/updated data on widgets
Hello, I have a small lightweight macOS application that includes a medium widget but the widget does not update with new data as often as I'd like. I understand that in apple's WidgetKit documentation they mention that apple controls when the widget updates due to battery life concerns, but I'd like to know if theres any way at all to control when the widget updates or when I think it makes sense to do so if I am not able to control how often it refreshes new data. https://github.com/Alexx1105/MacStat-v2.1
2
0
168
2w
macOS SwiftUI document app always shows file picker on startup
DESCRIPTION OF PROBLEM When my Document-based macOS SwiftUI app starts up, it always presents a document picker. I would like it to open any documents that were open when the app last quit, and if none were open, open an "Untitled" document. I understand that there is a setting in System Settings-> Desktop & Dock ("Close windows when quitting an application") that will cause windows to reopen when it is turned off, but I'd like to give users a chance to opt-in for reopening docs even when that is turned on, since it is difficult to find, on by default, and might not be the desired behavior for all apps. I don't see any way to get a list of currently open documents to persist them at shutdown. And even if that's considered a bad idea, I'd at least like a way to prevent the Document picker from being shown at startup and instead create an Untitled document if no documents were open. Ideally, I'd like a way to provide this functionality in SwiftUI that doesn't require macOS 15 or later STEPS TO REPRODUCE Create a SwiftUI macOS document application in Xcode using the provided template, Give it any name you want Run it, create a new ".exampletext" document, save it. Quit the app with the document open. Re-run the app, document picker is shown. Cancel the document picker and quit the app with no windows shown. Re-run the app, document picker is shown.
2
0
156
2w
SwiftData Master Details
I want to create master details relationship between patient and vitals signs so which of option codes below are better performance wise ? Option one is master - details done manually .. option 1 @Model class TestResult { @Attribute(.primaryKey) var id: UUID var patientID: UUID Option 2 @Model final class Vital { var patient: Patient?
0
0
111
2w
SwiftUI View cannot conform custom Equatable protocol in Swift 6.
In Swift 6, stricter concurrency rules can lead to challenges when making SwiftUI views conform to Equatable. Specifically, the == operator required for Equatable must be nonisolated, which means it cannot access @MainActor-isolated properties. This creates an error when trying to compare views with such properties: Error Example: struct MyView: View, Equatable { let title: String let count: Int static func ==(lhs: MyView, rhs: MyView) -> Bool { // Accessing `title` here would trigger an error due to actor isolation. return lhs.count == rhs.count } var body: some View { Text(title) } } Error Message: Main actor-isolated operator function '==' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode. Any suggestions? Thanks FB: FB15753655 (SwiftUI View cannot conform custom Equatable protocol in Swift 6.)
5
0
167
2w
UICollectionView Auto cell height problem
Hi, I'm trying to create a UICollectionView where the cell high is automatic. Cells contains a UILabel with all anchors to the contentView of the cell. It seems to work but I have a strange behavior with longer text, on reload data and on device rotation: Cells do not display the whole text or they change row, both randomly. To create my collection view I first create the collection view with a custom flow layout setting the automatic size on viewWillAppear: let collectionViewFlowLayout = CustomFlowLayout() collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout) and I have also overridden: override func willAnimateRotation(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { collectionView.setNeedsLayout() self.collectionView.layoutIfNeeded() self.collectionView.collectionViewLayout.invalidateLayout() //self.collectionView.reloadData() } Then, I created the custom layout as follow: import UIKit final class CustomFlowLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes] layoutAttributesObjects?.forEach({ layoutAttributes in if layoutAttributes.representedElementCategory == .cell { if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { layoutAttributes.frame = newFrame } } }) return layoutAttributesObjects } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard let collectionView = collectionView else { fatalError() } guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return nil } layoutAttributes.frame.origin.x = sectionInset.left if(indexPath.section == 0){ layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right } else if (indexPath.section == collectionView.numberOfSections - 1){ let width = ScreenUtility.getCollectionCellWidthForElement(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing, multiplier: 3) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElement(in: collectionView, at: indexPath, forElementHavingWidth: width, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing, multiplier: 3) layoutAttributes.frame.size.width = width } else if (indexPath.section == collectionView.numberOfSections - 3) || (indexPath.section == collectionView.numberOfSections - 4){ let width = ScreenUtility.getCollectionCellWidthForElement(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElement(in: collectionView, at: indexPath, forElementHavingWidth: width, sectionLeft: sectionInset.left, sectionRight: sectionInset.right, minimumInteritemSpacing: minimumInteritemSpacing) layoutAttributes.frame.size.width = width } else { let width = ScreenUtility.getCollectionCellSizeForElementFullRow(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right) layoutAttributes.frame.origin.x = ScreenUtility.getCollectionCellOriginForElementFullRow(in: collectionView, sectionLeft: sectionInset.left, sectionRight: sectionInset.right) layoutAttributes.frame.size.width = width } return layoutAttributes } } And finally on collection view cells: override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { setNeedsLayout() layoutIfNeeded() let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) return layoutAttributes } override func prepareForReuse() { self.nameLabel.text = "" self.idLabel.text = "" self.contentView.setNeedsLayout() self.contentView.layoutIfNeeded() } Let me show you an example on the iPad that is the worst. First Time I open the collection view I have cells on wrong rows and not sized properly Then I rotate the device portrait and the cells are fine On landscape again it changes behavior: This is just an example, things happens apparently randomly, and also sometimes cells disappear (I think the height is set to 0). I really do not understand why, cells width seems to be computed correctly, and cell label is set via setter: open var step: String = "" { didSet { nameLabel.text = step nameLabel.sizeToFit() self.contentView.setNeedsLayout() self.contentView.layoutIfNeeded() } }
2
0
153
2w
Show new Format Panel on button press
I'm working on integrating the new format panel shown in the WWDC24 session "What's New in UIKit" under the Text Improvements section. So far, I've implemented long-press functionality on a text passage, allowing the editing options to appear. From there, you can go to Format > More..., which successfully opens the new format panel. However, I would also like to add a button to programmatically display this format panel—similar to how the Apple Notes app has a button in the keyboard toolbar to open it. Does anyone know how to achieve this? Here's my current code for the text editor (I've enabled text formatting by setting allowsEditingTextAttributes to true): struct TextEditorView: UIViewRepresentable { @Binding var text: String func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIView(context: Context) -> UITextView { let textEditorView = UITextView() textEditorView.delegate = context.coordinator textEditorView.allowsEditingTextAttributes = true return textEditorView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = text } class Coordinator: NSObject, UITextViewDelegate { var parent: TextEditorView init(_ uiTextView: TextEditorView) { self.parent = uiTextView } func textViewDidChange(_ textView: UITextView) { self.parent.text = textView.text } } } Thanks in advance for any guidance!
0
0
127
2w
custom EnvironmentKey lookup causes compiler error
I receive the following compiler error: Cannot infer key path from context; consider explicitly specifying a root type when I attempt an @Environment(\.foodRepository) lookup in a descendant View. Here's the setup in my App class: import SwiftUI import SwiftData @main struct BulkCutApp: App { private var foodRepository: FoodRepository = /* some code*/ var body: some Scene { WindowGroup { ContentView() .foodRepository(foodRepository) } } } extension View { func foodRepository(_ customValue: FoodRepository) -> some View { environment(\.foodRepository, customValue) } } extension EnvironmentValues { var foodRepository: FoodRepository { get { self[FoodRepositoryKey.self] } set { self[FoodRepositoryKey.self] = newValue } } } struct FoodRepositoryKey: EnvironmentKey { static var defaultValue: FoodRepository = FoodRepository(food:[]) } Nothing special in FoodRepository: @Observable class FoodRepository { var food: [Food] // more code }
0
0
78
2w
Store SwiftUI Color in SwiftData
I have an app that needs to store a SwiftUI Color within SwiftData and I was wondering if anyone had found a way to do so easily and accurately. I'd prefer not to have to store the Color components (e.g. RGB values) and would ideally like to have a single variable in the @Model that stores the Color. I had considered using an extension to the Color type to create a HEX encoded String of the Color and an initializer that creates a Color from the HEX encoded String. Unfortunately, doing so proved not to be accurate due data loss when converting component values to integers. When testing this in Photoshop, the original color #FBAA1D became #FFAB00. Is there a way to accurately store the Color in SwiftData, possibly using a binary conversion to Data or somehow storing the Color.Resolved, which itself does not appear to be compatible with SwiftData. Any thoughts on how to best store the Color accurately within SwiftData would be greatly appreciated.
2
0
206
2w
App behavior changed under Sequoia 15.1.
I have an old Objective-C app that has been running for several years. The last compilation was in February 2024. I just upgraded to Sequoia 15.1. The app has four subviews on its main view. When I run the app only the subview that was the last one instantiated is visible. I know the other subviews are there, because a random mouse click in one invisible view causes the expected change in the visible view. What changed in 15.1 to cause this?
4
0
215
2w
SwiftUI not observing SwiftData changes
I have an app with the following model: @Model class TaskList { @Attribute(.unique) var name: String // Relationships var parentList: TaskList? @Relationship(deleteRule: .cascade, inverse: \TaskList.parentList) var taskLists: [TaskList]? init(name: String, parentTaskList: TaskList? = nil) { self.name = name self.parentList = parentTaskList self.taskLists = [] } } If I run the following test, I get the expected results - Parent has it's taskLists array updated to include the Child list created. I don't explicitly add the child to the parent array - the parentList relationship property on the child causes SwiftData to automatically perform the append into the parent array: @Test("TaskList with children with independent saves are in the database") func test_savingRootTaskIndependentOfChildren_SavesAllTaskLists() async throws { let modelContext = TestHelperUtility.createModelContext(useInMemory: false) let parentList = TaskList(name: "Parent") modelContext.insert(parentList) try modelContext.save() let childList = TaskList(name: "Child") childList.parentList = parentList modelContext.insert(childList) try modelContext.save() let fetchedResults = try modelContext.fetch(FetchDescriptor<TaskList>()) let fetchedParent = fetchedResults.first(where: { $0.name == "Parent"}) let fetchedChild = fetchedResults.first(where: { $0.name == "Child" }) #expect(fetchedResults.count == 2) #expect(fetchedParent?.taskLists.count == 1) #expect(fetchedChild?.parentList?.name == "Parent") #expect(fetchedChild?.parentList?.taskLists.count == 1) } I have a subsequent test that deletes the child and shows the parent array being updated accordingly. With this context in mind, I'm not seeing these relationship updates being observed within SwiftUI. This is an app that reproduces the issue. In this example, I am trying to move "Finance" from under the "Work" parent and into the "Home" list. I have a List that loops through a @Query var taskList: [TaskList] array. It creates a series of children views and passes the current TaskList element down into the view as a binding. When I perform the operation below the "Finance" element is removed from the "Work" item's taskLists array automatically and the view updates to show the removal within the List. In addition to that, the "Home" item also shows "Finance" within it's taskLists array - showing me that SwiftData is acting how it is supposed to - removed the record from one array and added it to the other. The View does not reflect this however. While the view does update and show "Finance" being removed from the "Work" list, it does not show the item being added to the "Home" list. If I kill the app and relaunch I can then see the "Finance" list within the "Home" list. From looking at the data in the debugger and in the database, I've confirmed that SwiftData is working as intended. SwiftUI however does not seem to observe the change. ToolbarItem { Button("Save") { list.name = viewModel.name list.parentList = viewModel.parentTaskList try! modelContext.save() dismiss() } } To troubleshoot this, I modified the above code so that I explicitly add the "Finance" list to the "Home" items taskLists array. ToolbarItem { Button("Save") { list.name = viewModel.name list.parentList = viewModel.parentTaskList if let newParent = viewModel.parentTaskList { // MARK: Bug - This resolves relationship not being reflected in the View newParent.taskLists?.append(list) } try! modelContext.save() dismiss() } } Why does my explicit append call solve for this? My original approach (not manually updating the arrays) works fine in every unit/integration test I run but I can't get SwiftUI to observe the array changes. Even more strange is that when I look at viewModel.parentTaskList.taskLists in this context, I can see that the list item already exists in it. So my code effectively tries to add it a second time, which SwiftData is smart enough to prevent from happening. When I do this though, SwiftUI observes a change in the array and the UI reflects the desired state. In addition to this, if I replace my custom list rows with an OutlineGroup this issue doesn't manifest itself. SwiftUI stays updated to match SwiftData when I remove my explicit array addition. I don't understand why my views, which is passing the TaskList all the way down the stack via Bindable is not updating while an OutlineGroup does. I have a complete reproducible ContentView file that demonstrates this as a Gist. I tried to provide the source here but it was to much for the post. One other anecdote. When I navigate to the TaskListEditorScreen and open the TaskListPickerScreen I get the following series of errors: error: the replacement path doesn't exist: "/var/folders/07/3px_03md30v9n105yh3rqzvw0000gn/T/swift-generated-sources/@_swiftmacro_09SwiftDataA22UIChangeDetectionIssue20TaskListPickerScreenV9taskLists33_A40669FFFCF66BB4EEA5302BB5ED59CELL5QueryfMa.swift" I saw another post regarding these and I'm wondering if my issue is related to this. So my question is, do I need to handle observation of SwiftData models containing arrays differently in my custom views? Why do bindings not observe changes made by SwiftData but they observe changes made explicitly by me?
1
0
183
2w
Get SwiftUI Image Data
I’m looking for the easiest and most efficient way to convert a SwiftUI Image to Data so that I can store it in SwiftData. let image: Image let data: Data = GetImageData(image: image) How would I implement the GetImageData function above? I have found examples of how to do so with UIImage but not Image.
1
0
172
2w
[macOS sequoia] keyboard shortcut for standard deviation (sigma) symbol not working
I'm doing statistical formulas and need the keyboard shortcut of the symbol used to represent standard deviation (sigma), which should look like (σ). Everything online suggests using the keyboard shortcut for option + w, but when I use that shortcut I get, ∑ instead. I've tried searching OS settings and there doesn't seem to be a place to change or determine what is the proper keyboard shortcut. The keyboard shortcut for statistical mean (mu) is working, µ And greater than or equal to, ≥ And less than or equal to, ≤ are also working.
1
0
175
2w
No ObservableObject of Type "" found.
Im building an recipe app for the social media of my mother. i already have the functionality for the users, when a user gets created an empty array gets initiated at the database named favoriteRecipes, which stores the id of his favorite recipes to show in a view. This is my AuthViewModel which is relevant for the user stuff: import Firebase import FirebaseAuth import FirebaseFirestore protocol AuthenticationFormProtocol { var formIsValid: Bool { get } } @MainActor class AuthViewModel : ObservableObject { @Published var userSession: FirebaseAuth.User? @Published var currentUser: User? @Published var currentUserId: String? init() { self.userSession = Auth.auth().currentUser Task { await fetchUser() } } func signIn(withEmail email: String, password: String) async throws { do { let result = try await Auth.auth().signIn(withEmail: email, password: password) self.userSession = result.user await fetchUser() // fetch user sonst profileview blank } catch { print("DEBUG: Failed to log in with error \(error.localizedDescription)") } } func createUser(withEmail email: String, password: String, fullName: String) async throws { do { let result = try await Auth.auth().createUser(withEmail: email, password: password) self.userSession = result.user let user = User(id: result.user.uid, fullName: fullName, email: email) let encodedUser = try Firestore.Encoder().encode(user) try await Firestore.firestore().collection("users").document(result.user.uid).setData(encodedUser) await fetchUser() } catch { print("Debug: Failed to create user with error \(error.localizedDescription)") } } func signOut() { do { try Auth.auth().signOut() // sign out user on backend self.userSession = nil // wipe out user session and take back to login screen self.currentUser = nil // wipe out current user data model } catch { print("DEBUG: Failed to sign out with error \(error.localizedDescription)") } } func deleteAcocount() { let user = Auth.auth().currentUser user?.delete { error in if let error = error { print("DEBUG: Error deleting user: \(error.localizedDescription)") } else { self.userSession = nil self.currentUser = nil } } } func fetchUser() async { guard let uid = Auth.auth().currentUser?.uid else { return } currentUserId = uid let userRef = Firestore.firestore().collection("users").document(uid) do { let snapshot = try await userRef.getDocument() if snapshot.exists { self.currentUser = try? snapshot.data(as: User.self) print("DEBUG: current user is \(String(describing: self.currentUser))") } else { // Benutzer existiert nicht mehr in Firebase, daher setzen wir die userSession auf nil self.userSession = nil self.currentUser = nil } } catch { print("DEBUG: Fehler beim Laden des Benutzers: \(error.localizedDescription)") } } } This is the code to fetch the favorite recipes, i use the id of the user to access the collection and get the favoriteRecipes out of the array: import SwiftUI @MainActor class FavoriteRecipeViewModel: ObservableObject { @Published var favoriteRecipes: [Recipe] = [] @EnvironmentObject var viewModel: AuthViewModel private var db = Firestore.firestore() init() { Task { await fetchFavoriteRecipes() } } func fetchFavoriteRecipes() async{ let userRef = db.collection("users").document(viewModel.userSession?.uid ?? "") do { let snapshot = try await userRef.collection("favoriteRecipes").getDocuments() let favoriteIDs = snapshot.documents.map { $0.documentID } let favoriteRecipes = try await fetchRecipes(recipeIDs: favoriteIDs) } catch { print("DEBUG: Failed to load favorite recipes for user: \(error.localizedDescription)") } } func fetchRecipes(recipeIDs: [String]) async throws -&gt; [Recipe] { var recipes: [Recipe] = [] for id in recipeIDs { let snapshot = try await db.collection("recipes").document(id).getDocument() if let recipe = try? snapshot.data(as: Recipe.self) { recipes.append(recipe) } } return recipes } } Now the Problem occurs at the build of the project, i get the error SwiftUICore/EnvironmentObject.swift:92: Fatal error: No ObservableObject of type AuthViewModel found. A View.environmentObject(_:) for AuthViewModel may be missing as an ancestor of this view. I already passed the ViewModel instances as EnvironmentObject in the App Struct. import SwiftUI import FirebaseCore class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { FirebaseApp.configure() return true } } @main struct NimetAndSonApp: App { @StateObject var viewModel = AuthViewModel() @StateObject var recipeViewModel = RecipeViewModel() @StateObject var favoriteRecipeViewModel = FavoriteRecipeViewModel() @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() .environmentObject(viewModel) .environmentObject(recipeViewModel) .environmentObject(favoriteRecipeViewModel) } } }
1
0
183
2w
can't install cocoaPods
need to use CocoaPods, Ruby, and Xcode to set up a development environment. trying to install CocoaPods and running into compatibility issues with Ruby versions (>= 2.7.0) and can't use rbenv.
1
0
141
2w
NSExtensionPointIdentifier key "com.apple.quicklook.preview" - which iOS versions are supported?
I am creating an iOS app to install on legacy iPads running iOS 9 and up, using XCode 13.4.1 which is the latest version that will support iOS below 11. The app is working fine but I just added a QuickLook Preview extension, and on iOS 10.3.1 it will not install due to the following error: This app contains an app extension that specifies an extension point identifier that is not supported on this version of iOS for the value of the NSExtensionPointIdentifier key in its Info.plist. Domain: com.apple.dt.MobileDeviceErrorDomain Code: -402653007 The NSExtensionPointIdentifier key in Info.plist is set by XCode automatically to "com.apple.quicklook.preview". I want to set the iOS Deployment Target to the lowest iOS version that will support this configuration. The documentation does not provide any guide as to which specific NSExtensionPointIdentifier keys are compatible with which iOS version. It just says 8+ for the whole list. Trial-and-error is limited by availability of legacy Simulators. If anyone can point to documentation that indicates which iOS is supported by which NSExtensionPointIdentifier key com.apple.quicklook.preview, I would be very grateful. Thanks (I understand about lack of App Store support etc, this is an app for my use on old iPads)
0
0
119
2w
SwiftData error "Thread 1: Fatal error: Composite Coder only supports Keyed Container"
I'm using SwiftData to store data in my app and I recently had to store both image data and colors. I have therefore added two variables to my model, one of type Data? and the other of type Color.Resolved? If both are set to nil then I can call context.save() without any error but when providing a value of type Color.Resolved, the following error message occurs: Thread 1: Fatal error: Composite Coder only supports Keyed Container. Any guidance on how to solve this and what needs to be done to store image data and colors with SwiftData?
1
0
143
2w
question about error
I am trying to work on a new app but everytime I try to run it and test it I get this error error reading dependency file '/Users/jacobwright/Library/Developer/Xcode/DerivedData/LevelingUp:_Life-baixnmqgtntqiacdkadvwrgeanox/Build/Intermediates.noindex/LevelingUp: Life.build/Debug-iphonesimulator/LevelingUp: Life iOS.build/Objects-normal/arm64/LevelingUp: Life iOS-master-emit-module.d': unexpected character in prerequisites and I do not know what to do. I even tryed makeing a new project and running it with out doing anything and I get the same thing I have tried Deleting Xcode and Reinstalling, and updating my computer and Xcode. I am not sure what else to try and I was wondering if anyone else is getting this and how do i fix it?
1
0
109
2w
Hide TabItems?
Is there really no way to hide a TabItem using the built-in TabView? I have 6 pages, but the 6th one I want hidden from the bottom tab bar, because I have a button that programmatically navigates to it on the navigation bar. I did not want to have to code a custom tab bar due to losing some useful features like pop to root in Navigation Stack.
0
0
123
2w