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

@Observable and didSet?
I'm in the process of migrating to the Observation framework but it seems like it is not compatible with didSet. I cannot find information about if this is just not supported or a new approach needs to be implemented? import Observation @Observable class MySettings { var windowSize: CGSize = .zero var isInFullscreen = false var scalingMode: ScalingMode = .scaled { didSet { ... } } ... } This code triggers this error: Instance member 'scalingMode' cannot be used on type 'MySettings'; did you mean to use a value of this type instead? Anyone knows what needs to be done? Thanks!
9
3
3.8k
Jun ’23
.refreshable on macOS?
Is .refreshable supposed to do anything on macOS? Works fine on iOS and iPadOS but it's not triggered on macOS. It's available since macOS 12 but the documentation doesn't mention anything about that. https://developer.apple.com/documentation/swiftui/view/refreshable(action:)
2
1
981
Jun ’23
Does code at 04:41 compile?
The code for @State doesn't seem to work. struct DonutListView: View { var donutList: DonutList @State private var donutToAdd: Donut? var body: some View { List(donutList.donuts) { DonutView(donut: $0) } Button("Add Donut") { donutToAdd = Donut() } .sheet(item: $donutToAdd) { // <-- would need a "donut in" TextField("Name", text: $donutToAdd.name) // <-- donutToAdd is optional and I'm not sure how it would be unwrapped Button("Save") { donutList.donuts.append(donutToAdd) donutToAdd = nil } Button("Cancel") { donutToAdd = nil } } } } Does anyone have a fix for this? Thanks, Dan!
1
2
906
Jun ’23
iOS17 UITextView inputView becomFirstResponder does not work
Simplely, when we set UITextView.inputView and then call becomeFirstResponder, but the custom inputView could not show expectedly just like before. We test this code in iOS17 and below, while only iOS17 does not work. And xcode console print these logs: Failed to retrieve snapshot. -[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID -[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID -[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID -[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked: Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked: Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked: Unsupported action selector setShiftStatesNeededInDestination:autoShifted:shiftLocked:
48
17
32k
Jun ’23
Observation and MainActor
Previously, it was recommended to use the @MainActor annotation for ObservableObject implementation. @MainActor final class MyModel: ObservableObject { let session: URLSession @Published var someText = "" init(session: URLSession) { self.session = session } } We could use this as either a @StateObject or @ObservedObject: struct MyView: View { @StateObject let model = MyModel(session: .shared) } By moving to Observation, I need to the @Observable macro, remove the @Published property wrappers and Switch @StateObject to @State: @MainActor @Observable final class MyModel { let session: URLSession var someText = "" init(session: URLSession) { self.session = session } } But switching from @StateObject to @State triggers me an error due to a call to main-actor isolated initialiser in a synchronous nonisolated context. This was not the case with @StateObject of @ObservedObject. To suppress the warning I could : mark the initializer as nonisolated but it is not actually what I want Mark the View with @MainActor but this sounds odd Both solutions does not sound nice to my eye. Did I miss something here?
9
3
6.2k
Jun ’23
SwiftUI NavigationSplitView like Apple Music
In the Apple Music app on iPad (horizontal size class == .regular), when a selection is made from the Split View sidebar, the detail switches to a separate UINavigationController for that selection, where we can push/pop views. If we make a different selection from the sidebar, we get another UINavigationController to manipulate. If we return to the first selection, the detail view is still showing the stack contents for that controller. I am trying to get the same behavior from NavigationSplitView in SwiftUI, but the detail view will reset its presented controller to its root. I think this is because NavigationSplitView uses whatever NavigationStack it finds in the detail hierarchy to manage its contents, effectively erasing the per-view stack contents. I have tried various methods of saving and restoring the navigation path without any luck. Any ideas on how to approach this? I have included a very simple example to show what I'm talking about. import SwiftUI struct ExampleView: View { enum Selection: String, CaseIterable { case letters case numbers } @State private var selection: Selection? var body: some View { NavigationSplitView { List(selection: $selection) { ForEach(Selection.allCases, id: \.self) { selection in NavigationLink(value: selection) { Text(selection.rawValue.capitalized) } } } .navigationTitle("Sidebar") } detail: { switch selection { case .letters: self.lettersView case .numbers: self.numbersView default: Text("Make a selection") } } } var lettersView = LettersView() var numbersView = NumbersView() } struct ExampleView_Previews: PreviewProvider { static var previews: some View { ExampleView() } } // MARK: - struct LettersView: View { private let letters = ["a", "b", "c", "d", "e", "f"] @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { List { ForEach(letters, id: \.self) { letter in NavigationLink(value: letter) { Text(letter.uppercased()) } } } .navigationTitle("Letters") .navigationDestination(for: String.self) { letter in Text(letter.uppercased()).font(.largeTitle) } } } } // MARK: - struct NumbersView: View { private let numbers = Array(0..<6) @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { List { ForEach(numbers, id: \.self) { number in NavigationLink(value: number) { Text(String(number)) } } } .navigationTitle("Numbers") .navigationDestination(for: Int.self) { number in Text(String(number)).font(.largeTitle) } } } }
1
2
843
Jun ’23
No macro named 'Preview' - error
So I am trying to move an old project from ios16 to ios17... wanted to play around with the new previews, and animations and first error I get is the above. When I create a new project I can use the macro just fine. What is more: when I add a new swiftUI file I get the same error with the #Preview macro. I went through the project and target settings, making sure everything is set to ios17 and Swift5, but can't find any other settings. Cleared the build cache and rebuilt from scratch. Hoping someone else ran onto the same problem and found a solution? Without using #Preview
3
0
1.3k
Jun ’23
VisionOS Set Default Window Size
Is it possible to specify a default window size for a 2D window in visionOS? I know this is normally achieved by modifying the WindowGroup with .defaultSize(width:height:), but I get an error that this was not included in "xrOS". I am able to specify .defaultSize(width:height:depth:) for a volumetric window, but this doesn't have any effect when applied to a 2D one.
11
3
4.3k
Jun ’23
Pass @Query filter predicate from parent view in SwiftData
Hi all, I am starting using the new amazing SwiftData and I really like it! I have a question regarding how to pass the filter predicate from the parent view. In my app I have a simple case where I have a package that contains multiple items. When I package is selected a view is pushed with the list of items in that package. The Items view has a query as following: struct ScoreListView: View { [.....] @Query(filter: #Predicate<SWDItem> { item in item.package?.id == selectedPackage.id } ,sort: \.timestamp) var items: [SWDItem] [.....] var body: some View { [...] } The problem is that selectedPackage is not "yet" available when defining the @Query and I have the classic error "Cannot use instance member 'selectedPackage' within property initializer; property initializers run before 'self' is available". How can I structure the code to have the selected package available when the @Query is defined? Thank you a lot
6
0
2.7k
Jun ’23
Binding with ForEach or List doesn't work anymore when using @Observable macro
Hi. The binding in a ForEach or List view doesn't work anymore when using the @Observable macro to create the observable object. For example, the following are the modifications I introduced to the Apple's example called "Migrating from the Observable Object Protocol to the Observable Macro" https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro struct LibraryView: View { @Environment(Library.self) private var library var body: some View { List($library.books) { $book in BookView(book: book) } } } All I did was to add the $ to turn the reference to library.books into a binding but I got the error "Cannot find '$library' in scope" Is this a bug or the procedure to use binding in lists changed? Thanks
3
0
2k
Jun ’23
UIViewRepresentable animations
I've tried to animate custom UIViewRepresentable with SwitfUI animations, but it doesn't work. It just sets value without interpolation. What should i do to use interpolation values in UIKit views? My example shows two "progress bars" red one is UIKit view, blue one is SwiftUI version. Sliders controls value directly, randomize button changes value to random with 5s animation. When I press button SwiftUI progress bar animates exactly as it should, but UIKit's one just jumps to final position. Set block of animatableData inside Animatable extension not called. How can I use SwiftUI animation value interpolations for UIKit? import SwiftUI import UIKit class UIAnimationView: UIView { var progress: CGFloat = 0.5 { didSet { if self.progressConstraint != nil, self.innerView != nil { self.removeConstraint(self.progressConstraint!) } let progressConstraint = NSLayoutConstraint( item: innerView!, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: min(1.0, max(0.0001, progress)), constant: 0 ) self.addConstraint(progressConstraint) self.progressConstraint = progressConstraint self.layoutIfNeeded() } } var innerView: UIView? private var progressConstraint: NSLayoutConstraint? public override init(frame: CGRect) { super.init(frame: frame) self.performInit() } public required init?(coder: NSCoder) { super.init(coder: coder) self.performInit() } private func performInit() { let innerView = UIView() innerView.translatesAutoresizingMaskIntoConstraints = false self.addSubview(innerView) self.leadingAnchor.constraint(equalTo: innerView.leadingAnchor).isActive = true self.topAnchor.constraint(equalTo: innerView.topAnchor).isActive = true self.bottomAnchor.constraint(equalTo: innerView.bottomAnchor).isActive = true let progressConstraint = NSLayoutConstraint( item: innerView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: progress, constant: 0 ) self.progressConstraint = progressConstraint self.addConstraint(progressConstraint) self.innerView = innerView self.innerView!.backgroundColor = UIColor.red self.backgroundColor = UIColor.black } } struct AnimationTest: UIViewRepresentable { var progress: CGFloat typealias UIViewType = UIAnimationView func updateUIView(_ uiView: UIAnimationView, context: Context) { print("progress: \(progress) \(context.transaction.isContinuous)") uiView.progress = progress } func makeUIView(context: Context) -> UIAnimationView { let view = UIAnimationView() view.progress = progress return view } } extension AnimationTest: Animatable { var animatableData: CGFloat { get { return progress } set { print("Animation \(newValue)") progress = newValue } } } struct AnimationDebug: View { @State var progress: CGFloat = 0.75 var body: some View { VStack { AnimationTest(progress: progress) Spacer() VStack { Slider(value: $progress, in: 0...1) { Text("Progress") } } GeometryReader { gr in Color.blue .frame( width: gr.size.width * progress, height: 48) } .frame(height: 48) Button("Randomize") { withAnimation(Animation.easeInOut(duration: 5)) { progress = CGFloat.random(in: 0...1) } } } } } struct AnimationTest_Previews: PreviewProvider { static var previews: some View { AnimationDebug() } }
2
0
1.4k
Jun ’23
RealityView update closure
Apple docs for RealityView state: You can also use the optional update closure on your RealityView to update your RealityKit content in response to changes in your view’s state." Unfortunately, I've not been able to get this to work. All of my 3D content is programmatically generated - I'm not using any external 3D modeling tools. I have an object that conforms to @ObservableObject. Its @Published variables define the size of a programmatically created Entity. Using the initializer values of these @Published variables, the 1st rendering of the RealityView { content in } works like a charm. Basic structure is this: var body: some View { RealityView { content in // create original 3D content using initial values of @Published variables - works perfect } update: { content in // modify 3D content in response to changes of @Published variables - never works } Debug statements show that the update: closure gets called as expected - based upon changes in the viewModel's @Published variables. However, the 3D content never changes - even though the 3D content is based upon the @Published variables. Obviously, if the @Published variables are used in the 1st rendering, and the update: closure is called whenever changes occur to these @Published variables, then why isn't the update: closure updating the RealityKit content as described in the Apple docs? I've tried everything I can think of - including removing all objects in the update: closure and replacing them with the same call that populated them in the 1st rendering. Debug statements show that the new @Published values are correct as expected when the update: closure is called, but the RealityView never changes. Known limitation of the beta? Programmer error? Thoughts?
10
1
4.2k
Jul ’23
macOS widget preview error
Following article Creating a widget extension on developer.apple.com (https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension) I encountered a problem with XCode preview: it shows an error with message | RemoteHumanReadableError: Failed to launch agent | No plugin is registered to launch the process type widgetExtension. Can someone help me? macOS 13.4 XCode 14.3.1
5
0
2.5k
Jul ’23
Drag and Drop operations fail when executed from within the same List
I am working on creating a file viewer to browse a network directory as a way to introduce myself to iOS app development, and was trying to implement a feature that would allow users to drag and drop both files and folders onto another folder inside of the app to move items around. However, it seems that if the View that is set to draggable, and then the view that is set as the Drop Destination is in the same List, then the Drop Destination will not detect when the draggable view has been dropped onto it. Here is the structure of my code: List { Section(header: Text("Folders")) { ForEach($folders, id: \.id) { $folder in FolderCardView() .onDrop(of: [UTType.item], isTargeted: $fileDropTargeted, perform: { (folders, cgPoint) -> Bool in print("Dropped") return true }) } } Section(header: Text("Files")) { ForEach($files, id: \.id) { $file in FileCardView() .onDrag({ let folderProvider = NSItemProvider(object: file) return folderProvider }) } } } I have verified that the issue comes down to the list, because if I move both of the ForEach loops out on their own, or even into their own respective lists, the code works perfectly. I have not only tested this with the older .onDrop and .onDrag modifiers as shown above, but also the newer .draggable and .dropDestination modifiers, and the result is the same. Does anyone know if this is intended behavior? I really like the default styling that the List element applies to other elements within, so I am hoping that it might just be a bug or an oversight. Thanks!
3
0
836
Jul ’23
Crashes "[RenderBox] RB::Animation::size(RB::Animation::TermOrArg const*, unsigned long) EXC_BAD_ACCESS" on iOS 17
Recently, we got crash reports on "[RenderBox] RB::Animation::size(RB::Animation::TermOrArg const*, unsigned long) EXC_BAD_ACCESS" on iOS 17 only. Is this an iOS 17 beta issue? This is the crash log. ========= Incident Identifier: F64495FD-BD28-4C35-9AA6-B9CCFFE46689 Hardware Model: iPhone13,4 Process: ourapp [774] Path: /private/var/containers/Bundle/Application/88384E91-49B7-4AD3-ABB7-29569372166F/ourapp.app/ourapp Identifier: com.ourcompany.ourapp Version: 2.1.11 (4111) AppStoreTools: 14E221 AppVariant: 1:iPhone13,4:15 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.ourcompany.ourapp [891] Date/Time: 2023-07-10 20:39:42.0369 +0900 Launch Time: 2023-07-10 20:39:37.5495 +0900 OS Version: iPhone OS 17.0 (21A5277h) Release Type: Beta Baseband Version: 4.02.00 Report Version: 104 Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000235686558 Exception Codes: 0x0000000000000001, 0x0000000235686558 VM Region Info: 0x235686558 is not in any region. Bytes after previous region: 19621209 Bytes before following region: 13933224 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL unused __TEXT 23437adb8-2343d0000 [ 341K] r--/rw- SM=COW ...ed lib __TEXT ---> GAP OF 0x2000000 BYTES unused __TEXT 2363d0000-2363e4000 [ 80K] r--/r-- SM=COW ...ed lib __TEXT Termination Reason: SIGNAL 11 Segmentation fault: 11 Terminating Process: exc handler [774] Triggered by Thread: 0 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 0 name: Thread 0 Crashed: 0 RenderBox 0x00000001f56047bc 0x1f5588000 + 509884 1 RenderBox 0x00000001f561af9c 0x1f5588000 + 602012 2 RenderBox 0x00000001f55c3e38 0x1f5588000 + 245304 3 RenderBox 0x00000001f55c3c78 0x1f5588000 + 244856 4 SwiftUI 0x000000018c71f860 0x18bb78000 + 12220512 5 SwiftUI 0x000000018c71e7b8 0x18bb78000 + 12216248 6 SwiftUI 0x000000018cf003a4 0x18bb78000 + 20480932 7 SwiftUI 0x000000018c71d3dc 0x18bb78000 + 12211164 8 SwiftUI 0x000000018c71cbe0 0x18bb78000 + 12209120 9 SwiftUI 0x000000018bee7fa8 0x18bb78000 + 3604392 10 SwiftUI 0x000000018c167020 0x18bb78000 + 6221856 11 AttributeGraph 0x00000001b0027d10 0x1b0024000 + 15632 12 AttributeGraph 0x00000001b0027674 0x1b0024000 + 13940 13 AttributeGraph 0x00000001b00269cc 0x1b0024000 + 10700 14 SwiftUI 0x000000018bb96078 0x18bb78000 + 123000 15 SwiftUI 0x000000018d3926dc 0x18bb78000 + 25274076 16 SwiftUI 0x000000018bb8af20 0x18bb78000 + 77600 17 SwiftUI 0x000000018bb936e4 0x18bb78000 + 112356 18 SwiftUI 0x000000018bb8e0a4 0x18bb78000 + 90276 19 SwiftUI 0x000000018bb88ad4 0x18bb78000 + 68308 20 SwiftUI 0x000000018d3926a4 0x18bb78000 + 25274020 21 SwiftUI 0x000000018d392590 0x18bb78000 + 25273744 22 SwiftUI 0x000000018bc3a620 0x18bb78000 + 796192 23 SwiftUI 0x000000018c387328 0x18bb78000 + 8450856 24 SwiftUI 0x000000018c3873d4 0x18bb78000 + 8451028 25 UIKitCore 0x000000018a7edec8 0x18a106000 + 7241416 26 UIKitCore 0x000000018aee1438 0x18a106000 + 14529592 27 UIKitCore 0x000000018aee0990 0x18a106000 + 14526864 28 CoreFoundation 0x0000000187ff8800 0x187f27000 + 858112 29 CoreFoundation 0x0000000188003930 0x187f27000 + 903472 30 CoreFoundation 0x0000000187f9168c 0x187f27000 + 435852 31 CoreFoundation 0x0000000187fa3a24 0x187f27000 + 510500 32 CoreFoundation 0x0000000187fa86c0 0x187f27000 + 530112 33 GraphicsServices 0x00000001ca02a224 0x1ca029000 + 4644 34 UIKitCore 0x000000018a494d08 0x18a106000 + 3730696 35 UIKitCore 0x000000018a49496c 0x18a106000 + 3729772 36 ourapp 0x000000010406af94 main + 68 (AppDelegate.swift:20) 37 dyld 0x00000001aad404f8 0x1aad2b000 + 87288 ========= Thanks.
9
1
3.0k
Jul ’23
SwiftUI: onPreferenceChange not called if view contains if statement
Hi, I'm trying to build iOS app, but I found out that .onPreferenceChange has strange behaviour if the view contains an if statement below view which sets .preference. Here is an repository with minimal reproduction: https://github.com/Mordred/swiftui-preference-key-bug There should be displayed title text on the top and bottom of the screen. But the bottom is empty. If you delete if statement if true { at https://github.com/Mordred/swiftui-preference-key-bug/blob/main/PreferenceKeyBug/PreferenceKeyBug.swift then it works fine.
1
4
878
Jul ’23
SwiftUI DocumentGroup equivalent for UIDocumentBrowserViewController's additionalLeadingNavigationBarButtonItems, additionalTrailingNavigationBarButtonItems and customActions?
DocumentGroup and UIDocumentBrowserViewController similarly are both the entry point into your app. In macOS you have the menu bar where you can put document-independent functionality, but on iPadOS the only way I am aware of is to add buttons to the document browser's toolbar. Is there an equivalent to UIDocumentBrowserViewController's additionalLeadingNavigationBarButtonItems and additionalTrailingNavigationBarButtonItems when using DocumentGroup? For example, say you have a document-based app with a subscription and user account. In order to meet the account deletion requirement you can add an Account Settings button using additionalTrailingNavigationBarButtonItems (and to the menu bar in macOS)...but where does this type of functionality belong when using DocumentGroup? Requiring a user to open or create a document before they can sign out or delete their account doesn't seem like the right solution, nor does it seem like it would meet the requirements to "Make the account deletion option easy to find in your app", so I hope I'm just missing something. Also related, we use customActions to allow users to save existing documents as templates. Is there a way to do this with DocumentGroup? TIA!
1
4
653
Jul ’23
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
1.2k
Jul ’23