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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

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
3.7k
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.2k
Jul ’23
Fatal crash when using CoreData and deleting item from list with Section headers
Greetings - The following code appears to work, but when a list item is deleted from a Category section that contains other list items, the app crashes (error = "Thread 1: EXC_BREAKPOINT (code=1, subcode=0x180965354)"). I've confirmed that the intended item is deleted from the appData.items array - the crash appears to happen right after the item is deleted. I suspect that the problem somehow involves the fact that the AppData groupedByCategory dictionary and sortedByCategory array are computed properties and perhaps not updating as intended when an item is deleted? Or maybe the ContentView doesn't know they've been updated? My attempt to solve this by adding "appData.objectWillChange.send()" has not been successful, nor has my online search for solutions to this problem. I'm hoping someone here will either know what's happening or know I could look for additional solutions to try. My apologies for all of the code - I wanted to include the three files most likely to be the source of the problem. Length restrictions prevent me from including the "AddNewView" code and some other details, but just say the word if that detail would be helpful. Many, many thanks for any help anyone can provide! @main struct DeletionCrashApp: App { let persistenceController = PersistenceController.shared // Not sure where I should perform this command @StateObject var appData = AppData(viewContext: PersistenceController.shared.container.viewContext) var body: some Scene { WindowGroup { ContentView() .environment(\.managedObjectContext, persistenceController.container.viewContext) .environmentObject(appData) } } } import Foundation import SwiftUI import CoreData class AppData: NSObject, ObservableObject { // MARK: - Properties @Published var items: [Item] = [] private var fetchedResultsController: NSFetchedResultsController<Item> private (set) var viewContext: NSManagedObjectContext // viewContext can be read but not set from outside this class // Create a dictionary based upon the category var groupedByCategory: [String: [Item]] { Dictionary(grouping: items.sorted(), by: {$0.category}) } // Sort the category-based dictionary alphabetically var sortedByCategoryHeaders: [String] { groupedByCategory.map({ $0.key }).sorted(by: {$0 < $1}) } // MARK: - Methods func deleteItem(itemObjectID: NSManagedObjectID) { do { guard let itemToDelete = try viewContext.existingObject(with: itemObjectID) as? Item else { return // exit the code without continuing or throwing an error } viewContext.delete(itemToDelete) } catch { print("Problem in the first do-catch code: \(error)") } do { try viewContext.save() } catch { print("Failure to save context: \(error)") } } // MARK: - Life Cycle init(viewContext: NSManagedObjectContext) { self.viewContext = viewContext let request = NSFetchRequest<Item>(entityName: "ItemEntity") request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.name, ascending: true)] fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: viewContext, sectionNameKeyPath: nil, cacheName: nil) super.init() fetchedResultsController.delegate = self do { try fetchedResultsController.performFetch() guard let items = fetchedResultsController.fetchedObjects else { return } self.items = items } catch { print("failed to fetch items: \(error)") } } // end of init() } // End of AppData extension AppData: NSFetchedResultsControllerDelegate { func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { guard let items = controller.fetchedObjects as? [Item] else { return } self.items = items } } import SwiftUI import CoreData struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @EnvironmentObject var appData: AppData @State private var showingAddNewView = false @State private var itemToDelete: Item? @State private var itemToDeleteObjectID: NSManagedObjectID? var body: some View { NavigationView { List { ForEach(appData.sortedByCategoryHeaders, id: \.self) { categoryHeader in Section(header: Text(categoryHeader)) { ForEach(appData.groupedByCategory[categoryHeader] ?? []) { item in Text(item.name) .swipeActions(allowsFullSwipe: false) { Button(role: .destructive) { self.itemToDelete = appData.items.first(where: {$0.id == item.id}) self.itemToDeleteObjectID = itemToDelete!.objectID appData.deleteItem(itemObjectID: itemToDeleteObjectID!) // appData.objectWillChange.send() <- does NOT fix the fatal crash } label: { Label("Delete", systemImage: "trash.fill") } } // End of .swipeActions() } // End of ForEach(appData.groupedByReplacementCategory[categoryHeader] } // End of Section(header: Text(categoryHeader) } // End of ForEach(appData.sortedByCategoryHeaders, id: \.self) } // End of List .navigationBarTitle("", displayMode: .inline) .navigationBarItems( trailing: Button(action: { self.showingAddNewView = true }) { Image(systemName: "plus") } ) .sheet(isPresented: $showingAddNewView) { // show AddNewView here AddNewView(name: "") } } // End of NavigationView } // End of body } // End of ContentView extension Item { @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> { return NSFetchRequest<Item>(entityName: "ItemEntity") } @NSManaged public var category: String @NSManaged public var id: UUID @NSManaged public var name: String } extension Item : Identifiable { }
3
1
1.4k
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
695
Jul ’23
NavigationSplitView resetting when app enters background
I've been trying to build an app using NavigationSplitView and SwiftUI on iOS 16. I noticed that as soon almost as the app enters the background (sometimes I have to wait a few seconds before immediately reopening the app) the contents of the NavigationSplitView are reset. This behavior differs from a NavigationStack using essentially the same path and app structure. I'm wondering if anyone has any idea why this happens? I did a little investigation and can say I've noticed a few things If using a List with a selection item specified, the selection item is set to nil when the app enters the background. For NavigationSplitView this typically will reset the downstream Detail or Content view since the value is lost If using a List without the selection parameter specified this effect is mitigated but the view still is reset and things like scroll position are wiped despite no content changing. Self._printChanges() indicates the view is unchanged despite being reset to its initial state. Using Apple's own WWDC sample app this effect is reproduced https://developer.apple.com/documentation/swiftui/bringing_robust_navigation_structure_to_your_swiftui_app This sample app does have some logic that tries to persist the navigation path data but actually doesn't work anyway, but for testing purposes I commented this out Inside ContentView.swift // .task { // if let jsonData = navigationData { // navigationModel.jsonData = jsonData // } // for await _ in navigationModel.objectWillChangeSequence { // navigationData = navigationModel.jsonData // } // } This app is a good sample because you can toggle between NavigationStack and NavigationSplitView and the behavior is isolated to the NavigationSplitView, the NavigationStack does not immediately reset. Obviously state preservation is an option but adds quite a bit of overhead and things like scroll position are hard to reproduce exactly, and having to fall back on this when the app loses focus for just a few seconds isn't ideal, I'm wondering if there's a workaround or this is a bug especially since this was not present when using NavigationStack. I did test this on the latest iOS 17 beta with the same effect Including a video link showing the issue https://youtu.be/cKicWv_58_s I also tried making a small sample app using NavigationView with a 3 column layout and this works normally, so it seems to be isolated to NavigationSplitView I also included a small more simple sample than the WWDC sample below that can be used to showcase the issue and shows that NavigationView works fine import SwiftUI struct ContentView: View { @State var presentingNSV: Bool = false @State var presentingNV: Bool = false var body: some View { HStack { Button { presentingNSV.toggle() } label: { Text("NavigationSplitView") } Button { presentingNV.toggle() } label: { Text("NavigationView") } } .fullScreenCover(isPresented: $presentingNSV) { NSV(isPresented: $presentingNSV) } .fullScreenCover(isPresented: $presentingNV) { NV(isPresented: $presentingNV) } } } struct TestList: View { var body: some View { List(0..<1000) { item in Text("Item \(item)") } } } struct NSV: View { @Binding var isPresented: Bool var body: some View { let _ = Self._printChanges() NavigationSplitView { TestList() .toolbar { ToolbarItem { Button { isPresented = false } label: { Text("Back") } } } } content: { TestList() } detail: { TestList() } } } struct NV: View { @Binding var isPresented: Bool var body: some View { let _ = Self._printChanges() NavigationView { TestList() .toolbar { ToolbarItem { Button { isPresented = false } label: { Text("Back") } } } TestList() TestList() } .navigationViewStyle(.columns) } } Video using this sample code https://youtu.be/GAiRL8TprrM
2
2
1.1k
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
2.7k
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
539
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.1k
Jul ’23
How to remove a StateObject from memory
Hi everyone, I have a content view that declares a StateObject @StateObject var appModel: AppModel = AppModel.instance I present the content view from a uikit view: let swiftUIView = ContentView() let hostingController = UIHostingController(rootView: swiftUIView) hostingController.modalPresentationStyle = .fullScreen DispatchQueue.main.async{ self.present(hostingController, animated: true, completion: nil) } I dismiss the contentview this way: struct DismissingView: View { @Environment(\.dismiss) var dismiss var body: some View { Button(action: { dismiss() } , label: { VStack(spacing: 10) { Image(systemName: "xmark") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 22) } .foregroundColor(.white) }) } } when I dismiss the content view I want to deallocate everything, but the stateobject remains. I have tried changing it to an observedObject with no success. Any idea how to deallocate everything? Thank you
1
0
587
Jul ’23
NavigationView and ScrollView = Extra Padding?
Im having an issue with my View. When ever i want to put it inside of a ScrollView there is extra padding that appears. I tested to find the cause of it but to no luck. Here is the code for it : NavigationView{ NavigationLink(destination: HiringAdPage(favorite: true)) { HiringAds() } .buttonStyle(PlainButtonStyle()) } the ScrollPart of it : ScrollView{ VStack(spacing: 0) { ForEach(0..<5) {index in HiringAdsView() } } } Someone please help been trying for a while now..
1
0
514
Jul ’23
visionOS - Positioning and sizing windows
Hi, In the visionOS documentation Positioning and sizing windows - Specify initial window position In visionOS, the system places new windows directly in front of people, where they happen to be gazing at the moment the window opens. Positioning and sizing windows - Specify window resizability In visionOS, the system enforces a standard minimum and maximum size for all windows, regardless of the content they contain. The first thing I don't understand is why it talk about macOS in visionOS documentation. The second thing, what is this page for if it's just to tell us that on visionOS we have no control over the position and size of 2D windows. Whereas it is precisely the opposite that would be interesting. I don't understand this limitation. It limits so much the use of 2D windows under visionOS. I really hope that this limitation will disappear in future betas.
11
2
4k
Jul ’23
Why is a RealityView inside an ImmersiveSpace bound by what seems to be a Window?
I have an app that launches into an immersive space with a mixed immersion style. It appears like the Reality View has bounds that resemble a window. I would expect the bounds to not exist because it's an ImmersiveSpace. Why do they exist? And how can I remove these? This is the entire code: @main struct RealityKitDebugViewApp: App { var body: some Scene { ImmersiveSpace { ContentView() } } } struct ContentView: View { @State var logMessages = [String]() var body: some View { RealityView { content, attachements in let root = Entity() content.add(root) guard let debugView = attachements.entity(for: "entity_debug_view") else { return } debugView.position = [0, 0, 0] root.addChild(debugView) } update: { content, attachements in } attachments: { Color.blue .tag("entity_debug_view") } .onAppear(perform: { self.logMessages.append("Hello World") }) } }
3
0
1.1k
Jul ’23
SwiftUI Buttons in a List do not highlight when tapped
SwiftUI Buttons in a List no longer highlight when tapped. Seems to have stopped highlighting after iOS 16.0 I've only tested on an iPhone/simulators so not sure if iPad has the same issue. The issue has been carried over to iOS 17 Beta 4. My app does not feel Apple like as there is no visual feedback for the user when a button in the list is pressed. Does anyone know why this is occurring? Is this a bug on Apple's end?
4
6
2.3k
Jul ’23
SwiftUI - Adjust Map() scale/zoom
Hi, I'm looking through SwiftUI Map for SwiftUI documentation (including IOS17 Beta) for way to adjust Map() scale, or zoom level, while simultaneously showing user's location and heading, for which I'm doing this @State var position = MapCameraPosition = .userLocation(followsHeading: true, fallback: .automatic) Map(position: $position) It does not appear to be possible so am looking for confirmation. Thanks everyone.
3
1
2.9k
Jul ’23
@Observable does not conform with Equatable (and Hashable)
Since Xcode 15 beta 5, making a class with the @Observable macro no longer requires all properties to have an initialization value, as seen in the video. Just put an init that collects the properties and everything works correctly. @Observable final class Score: Identifiable { let id: Int var title: String var composer: String var year: Int var length: Int var cover: String var tracks: [String] init(id: Int, title: String, composer: String, year: Int, length: Int, cover: String, tracks: [String]) { self.id = id self.title = title self.composer = composer self.year = year self.length = length self.cover = cover self.tracks = tracks } } But there is a problem: the @Observable macro makes each property to integrate the @ObservationTracked macro that seems not to conform the types to Equatable, and in addition, to Hashable. Obviously, being a feature of each property, it is not useful to conform the class in a forced way with the static func == or with the hash(into:Hasher) function that conforms both protocols. That any class we want to be @Observable does not conform to Hashable, prevents any instance with the new pattern to be usable within a NavigationStack using the data driven navigation bindings and the navigationDestination(for:) modifier. I understand that no one has found a solution to this. If you have found it it would be great if you could share it but mainly I am making this post to invoke the mighty developers at Apple to fix this bug. Thank you very much. P.S. - I also posted a Feedback (FB12535713), but no one replies. At least that I see.
3
4
1.9k
Jul ’23
Xcode 15: Disable the content margins for widget preview? (contentMarginsDisabled)
Hi guys, I am migrating my widgets to iOS 17 and because I already manage my layout margins, I just want to disable to new built-in widget content margins. I did it by using ".contentMarginsDisabled()" on the WidgetConfiguration and it works fine at run time. WIDGET CODE struct MyWidget: Widget { let kind: String = "MyWidget" var body: some WidgetConfiguration { return IntentConfiguration(kind: kind, intent: MyWidgetIntent.self, provider: WidgetProvider<MyWidgetIntent>()) { entry in WidgetView<MyWidgetIntent>(entry: entry) } .configurationDisplayName("My Widget") .supportedFamilies([WidgetFamily.systemMedium]) .contentMarginsDisabled() // <-- HERE } } RESULT Nevertheless, when previewing the WidgetView in a WidgetPreviewContext I didn't find anyway to disable the content margins (because manipulating directly the view and not a WidgetConfiguration). PREVIEW CODE struct MyWidget_Previews: PreviewProvider { static var previews: some View { WidgetView<MyWidgetIntent>(entry: WidgetEntry<MyWidgetIntent>()) // .padding(-16) Need to add this negative padding to disable margin .previewContext( WidgetPreviewContext(family: .systemMedium)) } } Do you know how to disable the content margins for widget preview?
2
0
2.9k
Aug ’23
Why @Bindable and not @Binding in SwiftUI for iOS 17
As Natascha notes in her helpful article https://tanaschita.com/20230807-migrating-to-observation/ pre-iOS17 was like this, Stateview Subview ----------------------------------------- Value Type @State @Binding Ref Type @StateObject @ObservedObject With iOS 17, it's like this: Stateview Subview ----------------------------------------- Value Type @State @Binding Ref Type @State @Bindable I like how they simplified @State and @StateObject into just @State for both cases. I'm curious, though, why didn't they simplify @Binding and @ObservedObject into just @Binding? Why did they need to maintain the separate property wrapper @Bindable? I'm sure there's a good reason, just wondering if anybody knew why. Interestingly, you can use both @Binding and @Bindable, and they both seem to work. I know that you're supposed to use @Bindable here, but curious why @Binding works also. import SwiftUI @Observable class TestClass { var myNum: Int = 0 } struct ContentView: View { @State var testClass1 = TestClass() @State var testClass2 = TestClass() var body: some View { VStack { Text("testClass1: \(testClass1.myNum)") Text("testClass2: \(testClass2.myNum)") // Note the passing of testClass2 without $. Xcode complains otherwise. ButtonView(testClass1: $testClass1, testClass2: testClass2) } .padding() } } struct ButtonView: View { @Binding var testClass1:TestClass @Bindable var testClass2:TestClass var body: some View { Button(action: { testClass1.myNum += 1 testClass2.myNum += 2 } , label: { Text("Increment me") }) } }
5
2
5.8k
Aug ’23
SwiftUI - Placing ToolbarItem on .keyboard does not work
I have a regular SwiftUI View embedded inside of a NavigationStack. In this view, I make use of the .searchable() view modifier to make that view searchable. I have a button on the toolbar placed on the .confirmationAction section, which is a problem when a User types into the search bar and the button gets replaced by the SearchBar's cancel button. Thus, I conditionally place the button, depending on whether a User is searching, either on the navigationBar or on the keyboard. The latter does not work however, as the button does not show and when trying to debug the View Hierarchy, Xcode throws an error saying the View Hierarchy could not be displayed. If I set the button to be on the .bottomBar instead, it shows up perfectly and the View Hierarchy also displays with no further issue. Has someone come across this issue and if so, how did you get it fixed? Thank you in advance.
21
11
7.3k
Aug ’23
@Observable/@State memory leak
Not sure if this code is supposed to leak memory or am I missing something? import SwiftUI import Observation @Observable class SheetViewModel { let color: Color = Color.red init() { print("init") } deinit { print("deinit") } } struct SheetView: View { @State var viewModel = SheetViewModel() var body: some View { Color(viewModel.color) } } @main struct ObservableMemoryLeakApp: App { @State var presented: Bool = false var body: some Scene { WindowGroup { Button("Show") { presented = true } .sheet(isPresented: $presented) { SheetView() } } } } Every time the sheet is presented/dismissed, a new SheetViewModel is created (init is printed) but it never released (deinit not printed). Also, all previously created SheetViewModel instances are visible in Memory Graph and have "Leaked allocation" badge. Reverting to ObservableObject/@StateObject fixes the issue, deinit is called every time the sheet is dismissed: -import Observation -@Observable class SheetViewModel { +class SheetViewModel: ObservableObject { - @State var viewModel = SheetViewModel() + @StateObject var viewModel = SheetViewModel() Does this mean there's a bug in Observation framework? Reported as FB13015569.
7
10
3.5k
Aug ’23
Implement preferences menu entry in MacCatalyst
I have an app which uses SwiftUI and Mac Catalyst. When running on a Mac I want to provide a preferences menu entry with the usual keyboard shortcut Command + ,. An implementation via the Settings bundle is out of question since my preferences are too complex for this. Here is a reduced example of my implementation: import SwiftUI @main struct PreferencesMenuTestApp: App { @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: UIResponder, UIApplicationDelegate { override func buildMenu(with builder: UIMenuBuilder) { let preferencesCommand = UIKeyCommand(title: "Preferences…", action: #selector(showPreferences), input: ",", modifierFlags: .command) // let preferencesCommand = UIAction(title: "Preferences…") { action in // debugPrint("show preferences") // } let menu = UIMenu(title: "Preferences…", options: .displayInline, children: [preferencesCommand]) builder.insertSibling(menu, afterMenu: .about) } @objc func showPreferences() { debugPrint("show preferences") } } The problem is that the menu entry is disabled. Obviously the provided selector is not recognised. When I mark the AppDelegate with @main, then the menu entry is enabled. Of course then the app's window is empty. When I switch to the UIAction implementation (the out commented code) it works fine. But since one cannot provide a keyboard shortcut for UIActions this is not a good solution. What am I missing? How would one implement a preferences menu entry that actually works?
3
0
987
Aug ’23