I'm trying to implement UI state restoration in an old Objective-C UIKit app that does not use scenes and also does not have a storyboard. I have implemented the correct AppDelegate methods -- application:shouldSaveSecureApplicationState: and application:shouldRestoreSecureApplicationState: -- and I can see that they are being called when expected.
I have also implemented the state restoration and UIViewControllerRestoration viewControllerWithRestorationIdentifierPath:coder: methods for the view controllers I want to persist and restore; along with correctly setting their restorationIdentifier and restorationClass properties. I can also see that those are being called when expected.
I've also installed the restorationArchiveTool and have verified that the persisted archive contains the expected view controllers and state.
However, once state restoration is complete, the window's rootViewController property is still nil and has not been assigned to the view controller that has the restorationIdentifier of the rootViewController at the time the state is persisted.
I found this sample app that does what I want to do -- persist and restore the state of the view controllers without the use of storyboards. Running that I verified that it does in fact work as expected.
https://github.com/darrarski/iOS-State-Restoration
The difference between what that app does and what mine does, is that it always creates the top level view controllers in application:willFinishLaunchingWithOptions:.
func application(_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let viewControllerA = DemoViewController()
viewControllerA.title = "A"
let navigationControllerA = UINavigationController(rootViewController: viewControllerA)
navigationControllerA.restorationIdentifier = "Navigation"
let viewControllerB = DemoViewController()
viewControllerB.title = "B"
let navigationControllerB = UINavigationController(rootViewController: viewControllerB)
navigationControllerB.restorationIdentifier = "Navigation"
let tabBarController = UITabBarController()
tabBarController.restorationIdentifier = "MainTabBar"
tabBarController.viewControllers = [navigationControllerA, navigationControllerB]
window = UIWindow(frame: UIScreen.main.bounds)
window?.restorationIdentifier = "MainWindow"
window?.rootViewController = tabBarController
return true
}
Unfortunately, my app is more dynamic and the rootViewController is determined after launch. When I updated the app to be structured more like mine, I see that it fails the same as mine and no longer restores the rootViewController.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var didRestoreState = false
func application(_ application: UIApplication,
willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.restorationIdentifier = "MainWindow"
return true
}
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if !didRestoreState {
let viewControllerA = DemoViewController()
viewControllerA.title = "A"
let navigationControllerA = UINavigationController(rootViewController: viewControllerA)
navigationControllerA.restorationIdentifier = "Navigation"
let viewControllerB = DemoViewController()
viewControllerB.title = "B"
let navigationControllerB = UINavigationController(rootViewController: viewControllerB)
navigationControllerB.restorationIdentifier = "Navigation"
let tabBarController = UITabBarController()
tabBarController.restorationIdentifier = "MainTabBar"
tabBarController.viewControllers = [navigationControllerA, navigationControllerB]
window?.rootViewController = tabBarController
}
window?.makeKeyAndVisible()
return true
}
func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool {
let libraryDirectory = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first
let appStateUrl = libraryDirectory?.appendingPathComponent("Saved Application State")
NSLog("Restoration files: \(appStateUrl?.path ?? "none")")
return true
}
func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, didDecodeRestorableStateWith coder: NSCoder) {
didRestoreState = true
}
}
I don't really understand why this doesn't work since the archive file looks identical in both cases, and the methods used to create and restore state of the view controllers are being called in both cases.
Is there something else I need to do to correctly restore the view controllers without having to create them all before state restoration begins?
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
SwiftUI Issues on iOS 16: App Freezes, Buttons Unresponsive, and Missing Data (Works Fine on iOS 17)
Hi everyone,
I’m experiencing significant issues with my SwiftUI app when running on iOS 16. These issues are not present in iOS 17, where everything works as expected. I’m hoping someone can provide insights or suggestions on how to address these problems.
The Problems
App Freezing:
In certain views, the app becomes completely unresponsive when running on iOS 16.
There are no clear patterns or console logs pointing to the source of the freeze.
Unresponsive Buttons:
Buttons stop working in some views. Tapping them does nothing, even though the logic and bindings are correct.
Missing Data:
Data fetched from services (remote APIs) or local storage doesn’t show up in the UI.
Expected Behavior
The app should handle user interactions and display data correctly on both iOS 16 and iOS 17, without freezes or unresponsive elements.
Environment:
Xcode Version: Xcode 15.4
Deployment Target: iOS 16
Testing Devices: iPhone 14 with iOS 17.6.1, iPhone 13 with iOS 18.1.1, iPhone 8 with iOS 16.4, iPhone 12 with 16.4, iPhone 8 Plus with iOS 16.0, iPhone 8 Plus with 16.7.10
Topic:
UI Frameworks
SubTopic:
SwiftUI
If two NavigationStacks are nested with the inner stack in a sheet NavigationLinks in the inner stack open as expected in the inner stack.
struct ContentView: View {
var body: some View {
NavigationStack {
Color.clear
.sheet(isPresented: .constant(true)) {
NavigationStack {
ExampleList()
.navigationTitle("Inner Navigation Stack")
}
.presentationDetents([.medium])
}
.navigationTitle("Outer Navigation Stack")
}
}
}
If I try the same with an overlay instead of a sheet, NavigationLinks in the inner stack unexpectedly open in the outer stack.
struct ContentView: View {
var body: some View {
NavigationStack {
Color.clear
.overlay(alignment: .bottomTrailing) {
NavigationStack {
ExampleList()
.navigationTitle("Inner Navigation Stack")
}
.frame(width: 200, height: 250)
.border(.black, width: 5)
.padding()
.presentationDetents([.medium])
}
.navigationTitle("Outer Navigation Stack")
}
}
}
Even the navigation title for the outer stack is being overridden by the inner stack's navigation title.
TLDR
What magic is sheet using that allows for nested NavigationStacks and how might I approach getting this to work in an overlay?
iOS 18.2
Xcode 16.2
The definition of ExampleList for reproducibility:
struct ExampleList: View {
var body: some View {
List(1..<5) { number in
NavigationLink("\(number)") {
Text("\(number)")
.font(.largeTitle)
}
}
}
}
I have a scroll view that scrolls horizontally and one of my users is asking that it respond to their scroll wheel without them having to use the shift key. Is there some way to do this natively? If not, how can I listen for the scroll wheel events in swiftUI and make my scroll wheel scroll to respond to them?
Using gesture recognizers it is easy to implement a long-press gesture to open a menu, show a preview or something else on the iOS platform. And you can provide the duration the user must hold down the finger until the gesture recognizer fires.
But I could not yet find out how to determine the default duration for a long-press gesture that is configured in the system settings within the "accessibility" settings under "Haptic Touch" (the available options are fast, standard and slow here).
Is it possible to read out this setting, so my App can adapt to this system setting as well?
I have to decrease main window screen size when user open Immersive space in my project.
Using frame i try it but it not updated main window size it just update view frame.
With iPadOS 18, the UITabBar now defaults to the floating style. I successfully reverted the tab bar to its traditional style by overriding the UITabBarController's horizontalSizeClass property:
self.tabBarController?.traitOverrides.horizontalSizeClass = .unspecified
When I launch the app on my Mac using Apple Silicon, TWO tab bars appear:
One appears at the bottom of the screen, like a traditional tab bar.
The second tab bar is still embedded in the app toolbar in its floating style.
Is this a bug? How do you ensure that overriding the horizontalSizeClass will remove/hide the floating tab bar when running an app on Apple Silicon? TIA!
(Demonstrated on a test project)
I made a macOS document-based app that has a second scene that's a Window. It's name appears in the single window list of the Windows menu, but has no assigned shortcut. I've tried the following to assign a shortcut to it, but it doesn't add a "⌘L" as I want:
Window("Logs", id: "logs") {
LogsView()
}
.keyboardShortcut("l")
I can brute-force this using .commands to replace the menu item but that seems crude and unnecessary. Is it the only way?
How do I draw a single line of text in a SwiftUI Canvas, scaled to fill a given rectangle?
Example:
Canvas { context, size in
let r = CGRect(origin: CGPointZero, size: size); // Whole canvas
let t = Text("Hello World");
context.draw(t, in: r);
}
Outside of Canvas I'd add .minimumScaleFactor(0) .lineLimit(1), and I guess set a large default font size, and I'd get the result I want.
But inside Canvas, .minimumScaleFactor and .lineLimit don't seem to be available; they return some View, not Text, which can't be used in context.draw. (Is there a trick to make that work?)
I have written the following to do this, but I think there must be an easier way to achieve this! Suggestions?
extension GraphicsContext {
mutating func draw_text_in_rect(string: String, rect: CGRect)
{
let text = Text(string) .font(.system(size: 25));
// The font size used here does matter, because e.g. letter spacing
// varies with the font size.
let resolved = resolve(text);
let text_size = resolved.measure(in: CGSize(width: CGFloat.infinity, height: CGFloat.infinity));
let text_aspect = text_size.width / text_size.height;
let fit_size = CGSize(width: min(rect.size.width, rect.size.height*text_aspect),
height: min(rect.size.height, rect.size.width/text_aspect));
let fit_rect = CGRect(x: rect.origin.x + (rect.size.width-fit_size.width)/2,
y: rect.origin.y + (rect.size.height-fit_size.height)/2,
width: fit_size.width,
height: fit_size.height);
let scale = fit_size.width / text_size.width;
// For debug:
// var p = Path();
// p.addRect(fit_rect);
// stroke(p, with: GraphicsContext.Shading.color(.red), lineWidth: 1);
translateBy(x: fit_rect.minX, y: fit_rect.minY);
scaleBy(x:scale, y:scale);
draw(resolved, at: CGPointZero, anchor: UnitPoint.topLeading);
transform = CGAffineTransformIdentity;
}
};
I am implementing a new Intents UI Extension and am noticing that the viewWillDisappear, viewDidDisappear, and deinit methods are not being called on my UIViewController that implements INUIHostedViewControlling, when pressing the "Done" button and dismissing the UIViewController.
This causes the memory for the UI Extension to slowly increase each time I re-run the UI Extension until it reaches the 120MB limit and crashes.
Any ideas as to what's going on here and how to solve this issue?
My app is the client in a client-server document management system. It supports scanning, indexing, and creation of various types documents including PDF, TIFF, various image types, and text. Upon installation of macOS 15.2, I am getting a strange NSInternalInconsistencyException error so long as the following are true:
I have created or opened a PDF (or other type) document
I click on the desktop/Finder or other app
Normally, I would expect this action to put my App in the background, but before that happens, the error is thrown. I am not connected any server at the time. My app is built catch unhandled exceptions and this is what is displayed:
At the time the error is thrown, [NSApp mainWindow] appears to be set to nil, but I have no idea if this occurred as result of becoming the background app or because of something I am doing wrong. I never set mainWindow anywhere in my app. I've tried to set a Waitchpoint or various waist try and catch when mainWindow changes, but have come up empty. Note the error is thrown if I hit a breakpoint when debugging in Xcode (because it switches to Xcode).
This errors never occurred with previous releases and does not occur when the app is run under 15.1. The app is written in ObjectiveC.
I've looked at various app-level flags and info.plist properties and nothing I've seen jumps out at me. I strongly suspect this error is a result of some system-level app attempting to create a UserActivity file (perhaps encrypted) that it can store in the cloud (a feature we would rather not use yet). It could also be trying to do an autosave on my open document-based windows - our NIB files that apply to our documents are marked as Restorable and they worked in prior system releases. Turning the Restorable flag off has no effect on the error.
Any clue what I might be missing here? I've spent an embarrassing number of days trying to understand why this is happening.
Topic:
UI Frameworks
SubTopic:
General
in ios it is not same as it in computer
there is text:"ยินดี
in computer is
but in ios it is
the fontsize is 16
I tried every font which is in ios and tried copy simsun in windows to ios and create CTFont
I draw it using UIGraphics drawString
Is there an easy way to allow users to tap on SwiftUI Text elements to highlight specific words e.g. copy ?
The .textSelection API works to select an entire block of text however it'd be great to confirm if there is an existing way with Text for individual words or if Apple plan on adding this ability at some point in the future.
In this UIKit app, I have to display numbers (from 1 to 100), in a label., on several lines, with 8 numbers on each line. Order is computed by the app for a specific purpose.
The numbers are separated by space. Label font is Helvetica Neue 15.0.
I want to get them aligned vertically.
So, I have a padding so that they are all the same length of 4.
Problem: the space have smaller width (half in fact) than digits, so alignment is disrupted:
Of course, I can use fixed width fonts (like Menlo), but I've not found one that fits (the zero is barred, which is not looking great in the app).
I have tried using
class func monospacedDigitSystemFont(
ofSize fontSize: CGFloat,
weight: UIFont.Weight
) -> UIFont
and apply to label.text. To no avail as it modifies only digits, not space char.
I have found a workaround, padding with 2 spaces instead of one,
but is there another solution ?
So I am looking for a space character that would have the same width as a digit. There existe thin space (https://en.wikipedia.org/wiki/Whitespace_character) but not larger space.
Does it exist ?
We have developed an iOS app using three fonts: PingFangSC Regular, PingFangSC Medium, and DINAlternate-Bold. Do all three fonts require commercial authorization to be used in the app?
Hello,
I am currently encountering an issue where SwiftUI View Previews cannot be displayed when the View is defined in a Static Framework target. This issue only occurs under specific conditions.
Environment
Xcode: 16.2
Scheme Structure:
MainApp
Test Target: TestHogeFeature
Test Setting:
Gather coverage (Code coverage collection) enabled(all)
Target Structure:
MainApp (Application target)
Dependencies: [HogeFeature, Core]
HogeFeature (Static Framework target)
Dependencies: [Core]
Core (Framework target)
Dependencies: None
TestHogeFeature (Unit test target)
Dependencies: [HogeFeature]
Summary
I am currently working on a SwiftUI-based project and have encountered an issue where Previews fail to display under specific conditions. Below are the details:
Issue
In the MainApp scheme, when the code coverage collection setting (Gather coverage for) is enabled, Previews for SwiftUI Views within the HogeFeature (Static Framework) target fail to display correctly. However, the issue is resolved by taking one of the following actions:
Change HogeFeature from a Static Framework to a Dynamic Framework.
Remove the build setting MACH_O_TYPE: staticlib
Disable the Gather coverage setting in the MainApp scheme.
I have attached the actual error log from the failed Preview.
preview error log
Questions
Why does this issue occur only when using a Static Framework with code coverage enabled?
Is there any way to resolve this issue while maintaining the current configuration (Static Framework with code coverage enabled)?
I would appreciate any advice or insights regarding the cause and potential solutions.
I'm getting a weird response from Xcode in trying to use symbolVariant(.contains). I also don't understand why it demands the type cast. What am I doing wrong?
Here's the code as text:
import SwiftUI
let Variants: [SymbolVariants] = [
.circle,
.square,
.fill,
.rectangle,
.slash,
.none
]
func varAvail(_ image: Image) -> [SymbolVariants] {
var res: [SymbolVariants] = []
for variant in Variants {
if image.symbolVariant(.contains(variant)) as! Bool {
res.append(variant)
}
}
}
Description
We are developing a app for iOS and iPadOS that involves extensive custom drawing of paths, shapes, texts, etc. To improve drawing and rendering speed, we use CARenderer to generate cached images (CGImage) on a background thread. We adopted this approach based on this StackOverflow post: https://stackoverflow.com/a/75497329/9202699.
However, we are experiencing frequent crashes in our production environment that we cannot reproduce in our development environment. Despite months of debugging and seeking support from DTS and the Apple Feedback platform, we have not been able to fully resolve this issue. Our recent crash reports indicate that the crashes occur when calling CATransaction.commit().
Crash traceback
The method names in this traceback are mapped to those in the code sample below. The app name has been masked.
Crashed: com.apple.root.user-initiated-qos.cooperative
0 MyApp 0x887408 specialized static CAUtils.commitCATransaction() + 4340151304 (<compiler-generated>:4340151304)
1 MyApp 0x887408 specialized static CAUtils.commitCATransaction() + 4340151304 (<compiler-generated>:4340151304)
2 MyApp 0x8874a4 specialized static CAUtils.addDrawingItemsToRenderer(xxx) + 250 (CAUtils.swift:250)
3 MyApp 0x887710 specialized static CAUtils.drawOnCGImageWithCARenderer(xxx) + 267 (CAUtils.swift:267)
4 MyApp 0x8878c0 specialized static CAUtils.drawOnCGImageWithCARendererWithRetry(xxx) + 315 (CAUtils.swift:315)
5 MyApp 0x736294 XXXManager.generateCGImages(xxx) + 570 (XXXManager.swift:570)
6 MyApp 0x73404c closure #1 in XXXManager.updateCachedCGImages(xxx) + 427 (XXXManager.swift:427)
7 libswift_Concurrency.dylib 0x61104 swift::runJobInEstablishedExecutorContext(swift::Job*) + 252
8 libswift_Concurrency.dylib 0x62514 swift_job_runImpl(swift::Job*, swift::SerialExecutorRef) + 144
9 libdispatch.dylib 0x15d8c _dispatch_root_queue_drain + 392
10 libdispatch.dylib 0x16590 _dispatch_worker_thread2 + 156
11 libsystem_pthread.dylib 0x4c40 _pthread_wqthread + 228
12 libsystem_pthread.dylib 0x1488 start_wqthread + 8
Code Sample
Below is a sample of our code. While the complete snippet is too long, the issue occurs in addDrawingItemsToRenderer. Please refer to the other methods for completeness and reference purposes.
private let transactionLock = NSLock()
private let deviceLock = NSLock()
private let device = MTLCreateSystemDefaultDevice()!
/// This is the method we call from outside.
@inline(never)
static func drawOnCGImageWithCARenderer(
layerRect: CGRect,
drawingItems: [DrawingItem]
)
-> CGImage? {
guard
let (texture, renderer) = addDrawingItemsToRenderer(
layerRect: layerRect,
drawingItems: drawingItems
) else {
return nil
}
renderer.beginFrame(atTime: 0, timeStamp: nil)
renderer.render()
renderer.endFrame()
guard
let colorSpace = CGColorSpace(name: CGColorSpace.sRGB),
let ciImage = CIImage(mtlTexture: texture, options: [.colorSpace: colorSpace]) else {
return nil
}
let context = CIContext()
return context.createCGImage(ciImage, from: ciImage.extent)
}
/// This is the method will the crash happens
@inline(never)
fileprivate static func addDrawingItemsToRenderer(
layerRect: CGRect,
drawingItems: [DrawingItem]
)
-> (MTLTexture, CARenderer)? {
// We have encapsulated everything related to CALayer and its
// associated creations and manipulations within CATransaction
// as suggested by engineers from Apple Feedback Portal.
beginCATransaction()
defer {
commitCATransaction() // The crash happens here
}
let (layer, imageWidth, imageHeight) =
addDrawingItemsToLayer(layerRect: layerRect, drawingItems: drawingItems)
return createTextureAndRenderer(
layer: layer,
imageWidth: imageWidth,
imageHeight: imageHeight
)
}
// Below are all internal methods. We have split the method into very
// granular parts and marked them as @inline(never) to prevent the
// compiler from inlining our code, which may otherwise obscure usage
// trackback information in our crash reports.
@inline(never)
fileprivate static func beginCATransaction() {
transactionLock.lock()
CATransaction.begin()
}
@inline(never)
fileprivate static func commitCATransaction() {
// From our crash report, we believe the crash happens on this line.
CATransaction.commit()
// It is unlikely that the lock cause the crash as we added it only recently
// to ensure that there is only one transaction on our background thread,
// and after we added this lock, the crash rate indeed lowered, but still
// not fully disappear
transactionLock.unlock()
}
--------------------------------
// The methods below are provided for reference and completeness. While // they may have issues, they do not frequently appear in our crash
// reports as the one caused by `CATransaction.commit()`
@inline(never)
fileprivate static func addDrawingItemsToLayer(
layerRect: CGRect,
drawingItems: [DrawingItem]
)
-> (layer: CALayer, imageWidth: CGFloat, imageHeight: CGFloat) {
let layer = CALayer()
layer.isGeometryFlipped = SharedAppUtils.isIOS
layer.anchorPoint = CGPoint.zero
layer.bounds = layerRect
layer.masksToBounds = true
for drawingItem in drawingItems {
// We have thousands or hundred thousands of drawing items to add.
// Each drawing item may produce a CALayer, CAShapeLayer or CATextLayer.
// This is also why we want to utilise CARenderer to leverage GPU rendering.
let sublayerForDrawingItem =
drawingItem.createCALayerOrCATextLayerOrCAShapeLayer()
layer.addSublayer(sublayerForDrawingItem)
}
let imageWidth = max(1, layer.frame.size.width * UIScreen.main.scale)
let imageHeight = max(1, layer.frame.size.height * UIScreen.main.scale)
layer.transform = CATransform3DMakeScale(UIScreen.main.scale, UIScreen.main.scale, 1)
layer.frame = .init(origin: .zero, size: .init(width: imageWidth, height: imageHeight))
return (layer, imageWidth, imageHeight)
}
@inline(never)
fileprivate static func createTextureAndRenderer(
layer: CALayer,
imageWidth: CGFloat,
imageHeight: CGFloat
)
-> (MTLTexture, CARenderer)? {
deviceLock.lock()
defer {
deviceLock.unlock()
}
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
pixelFormat: .rgba8Unorm,
width: Int(imageWidth),
height: Int(imageHeight),
mipmapped: false
)
textureDescriptor.usage = [MTLTextureUsage.shaderRead, .shaderWrite, .renderTarget]
guard
let texture = device.makeTexture(descriptor: textureDescriptor) else {
return nil
}
let renderer = CARenderer(mtlTexture: texture)
renderer.bounds = layer.frame
renderer.layer = layer.self
return (texture, renderer)
}
Description
Our app (and sample app) are using associated domains to support deep linking. As an unintended side effect we get full support for auto-filling passwords with the QuickType bar on our login screen. However, after the username and password fields are filled and the user taps the Login button, the keyboard stays on screen. We have tried everything I can think of including @FocusState and UIKit resignFirstResponder, among other things.
Our login screen is in a fullscreencover or sheet. When the sheet dismisses the keyboard is still present. In my sample app (and the code below) if I use a navigation stack and push the next view onto the stack, the keyboard closes.
I'm not able to provide a useful video because the iOS keyboard closes when focus is in a SecureField.
*Note: If we remove the associated domain from our app (and website) the backup iOS password functionality takes over and the keyboard works as expected.
Code
struct ContentView: View {
@State private var name: String = ""
@State private var password: String = ""
@State private var showLogin = false
@FocusState private var isFocused: Bool
var body: some View {
VStack {
Button("Login") {
showLogin.toggle()
}
}
.fullScreenCover(isPresented: $showLogin) {
VStack {
TextField("Enter your name", text: $name)
.textFieldStyle(.roundedBorder)
.focused($isFocused)
SecureField("Enter password", text: $password)
.autocapitalization(.none)
.autocorrectionDisabled(true)
.textContentType(.password)
.focused($isFocused)
Button("Login") {
isFocused = false
showLogin = false
}
.buttonStyle(.borderedProminent)
}
}
}
}
Steps to Reproduce
Launch sample app
Tap 'Login'
Place keyboard focus in the first text field (name)
Keyboard with QuickType bar opens
Tap 'Passwords'
Create a new password for this login item (choose any username)
Passwords will close
Tap 'Login' to close the sheet
Force close the app
Reopen the app
Tap 'Login'
Place keyboard focus in the first text field (name)
Keyboard with QuickType” bar opens
Tap the auto-fill password button (password for atomicrobot.com in my case)
User name and password fields are filled out
Keyboard with QuickType bar is still open; keyboard focus is in "password" field
Tap 'Login'
Sheet closes, keyboard is still open
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi everyone,
I'm currently facing an issue with AVAudioPlayer in my SwiftUI project. Despite ensuring that the sound file "buttonsound.mp3" is properly added to the project's resources (I dragged and dropped it into Xcode), the application is still unable to locate the file when attempting to play it.
Here's the simplified version of the code I'm using:
import SwiftUI
import AVFoundation
struct ContentView: View {
var body: some View {
VStack {
Button("Play sound") {
playSound(named: "buttonsound", ofType: "mp3")
}
}
}
}
func playSound(named name: String, ofType type: String) {
guard let soundURL = Bundle.main.url(forResource: name, withExtension: type) else {
print("Sound file not found")
return
}
do {
let audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch let error {
print("Error playing sound: \(error.localizedDescription)")
}
}