I'm trying to include Apple's Personal Voice feature in an app I'm working on, but I want to use a button or toggle to request access, rather than firing the request on first launch. The problem is that, if AVSpeechSynthesizer is used during the same session, before Personal Voice is authorized, the app has to be restarted to use the feature.
Here is a basic example that demonstrates the issue on my iPhone (running 18.1 beta, but the issue was present at least in 18.0, maybe before):
import AVFoundation
import SwiftUI
struct TestView: View {
let synthesizer = AVSpeechSynthesizer()
@State private var personalVoices: [AVSpeechSynthesisVoice] = []
var body: some View {
VStack(spacing: 100) {
Text("Personal Voices Available: \(personalVoices.count)")
Button {
speakUtterance(string: "Hello, world!")
} label: {
Image(systemName: "hand.wave.fill")
.font(.system(size: 100))
}
Button("Fetch Personal Voices") {
Task { await fetchPersonalVoices() }
}
}
}
func fetchPersonalVoices() async {
AVSpeechSynthesizer.requestPersonalVoiceAuthorization() { status in
if status == .authorized {
personalVoices = AVSpeechSynthesisVoice.speechVoices().filter { $0.voiceTraits.contains(.isPersonalVoice) }
}
}
}
func speakUtterance(string: String) {
let utterance = AVSpeechUtterance(string: string)
if let voice = personalVoices.first {
utterance.voice = voice
} else {
utterance.voice = AVSpeechSynthesisVoice(language: Locale.preferredLanguages[0])
}
synthesizer.speak(utterance)
}
}
If you tap the hand symbol first (before authorizing Personal Voice), you'll probably notice that the Personal Voices Available number never increases. If you authorize Personal Voice before tapping the hand symbol, it should speak using your Personal Voice as expected.
The example code is mostly taken directly from this WWDC23 video (Personal Voice info begins around the 10-minute mark).
Does anyone have any idea what could be causing this?
Note: Personal Voice can't be tested in Simulator. The code will need to be run on a physical device that has Personal Voice set up, to test.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Whan using a tabview set with a tabviewstyle of sidebaradaptable on macOS 15.1 beta 5 the tabs are non responsive and is basically broken.
Example code... If you click around on these tabs you will see it is not responsive. When you add a lot more tabs from a for loop for example you really get poor performance. But this is not the case with earlier beta releases.
TabView {
Tab("One", systemImage: "1.circle.fill") {
Text("Test One")
}
Tab("Two", systemImage: "2.circle.fill") {
Text("Test Two")
}
Tab("Three", systemImage: "3.circle.fill") {
Text("Test Three")
}
}
.tabViewStyle(.sidebarAdaptable)
With iOS 18.0, this snippet of code that has a NavigationSplitView inside a NavigationStack will not display the sidebar until the navigation transition is completed.
NavigationStack {
NavigationLink("Link") {
NavigationSplitView {
Text("Example")
} detail: {
Text("Does not appear")
}
}
}
Directly after pressing the link, a toolbar briefly appears. Once the transition is completed, the split view's sidebar appears and the toolbar disappears. The detail view does not visually appear at all.
The same problem occurs when using .navigationDestination(…), which I am in our production code.
I've tested this in Xcode 16.0 Previews for iOS 18.0, iPhone SE Simulator iOS 18.0, iPadOS 18.0 when horizontal size class is compact, and on my personal iPhone 13 mini iOS 18.0 I experienced this problem on our production app.
Is there any workaround to not have this delay? Our app is heavily built around this nested approach, and has been working perfectly in previous iOS versions.
I am encountering an issue with the UndoManager functionality in a SwiftUI application that integrates SwiftData for persistence. This issue occurs specifically in macOS 14 (Sonoma) but works as expected on macOS 15 (Sequoia).
The focused test app I have prepared for demonstration allows users to create ParentItem objects, and for each ParentItem, users can add multiple ChildItem objects. The undo functionality (via Cmd+Z) is not working as expected in Sonoma. When I try to undo a ChildItem addition, the UndoManager does not revert just the last ChildItem added, but instead removes all ChildItems that were added in that session.
Expected Behavior
On macOS 14 (Sonoma), I expect the UndoManager to undo only the most recent transaction (in this case, a single ChildItem insert), similar to how it functions on macOS 15 (Sequoia). Each ChildItem insertion should be treated as a separate undoable action.
Current Behavior
In macOS Sonoma, pressing Cmd+Z undoes the entire list of ChildItems added to a ParentItem in the current session, rather than just the most recent ChildItem. This appears to be an issue with undo grouping, but I’ve confirmed that no explicit grouping is being used.
Question
Is this an issue with UndoManager in macOS Sonoma, particularly in how it interacts with SwiftData persistence? What changes should I make to ensure that each ChildItem insert is treated as an individual undo action in macOS Sonoma, just as it works in Sequoia?
Any guidance on isolating the issue or recommended workarounds would be appreciated. I would expect that undo actions for each child addition would be treated as separate transactions, not grouped.
Steps Taken to Solve the Problem
I attempted to manually save the model context (modelContext.save()) after each ChildItem insert to ensure proper persistence.
I also verified that UndoManager was not grouping operations explicitly by calling beginUndoGrouping() or endUndoGrouping() myself.
This issue seems to be tied specifically to macOS Sonoma, as it does not occur on macOS Sequoia, where undoing behaves as expected.
Conditions
macOS 14 Sonoma: The issue occurs consistently.
macOS 15 Sequoia: The issue does not occur.
This issue appears to be independent of hardware, as I’ve tested it on multiple machines.
APIs/Features Potentially Involved
UndoManager in a SwiftUI application
SwiftData for persistence (using modelContext.save())
macOS version-specific behavior
Steps to reproduce
Clone test project (https://github.com/Maschina/SwiftDataUndoManagerExample), compile and run
Create a new ParentItem in the app (via plus toolbar button in the sidebar).
Add multiple ChildItems to the ParentItem (via plus toolbar button in the content / middle column of the navigation split view).
Press Cmd+Z to undo the last addition.
While working with the Emoji Rangers Sample Code, I noticed that .redacted(reason:) seems to ignore the minimumScaleFactor() modifier - I have reproduced this behaviour with Xcode 16 and Xcode 16.1 beta 2 on iOS and on the Mac:
struct ContentView: View {
@State private var isRedacted: Bool = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
.font(.largeTitle)
Toggle("Redacted", isOn: $isRedacted)
}
.padding()
.minimumScaleFactor(0.1)
.redacted(reason: isRedacted ? .placeholder : .invalidated)
}
}
As long as the minimumScaleFactor does not kick in, redacted seems to work as expected:
But then it does not:
I tried changing the order of both modifiers with no effect. Wonder if this is expected and there is a way to make it work so it preserves the scaled down layout or a bug?
Filed just in case: FB15270541 (.redacted(reason:) modifier ignores .minimumScaleFactor)
Currently for my SwiftUI application i'm using dismissWindow() to close my windows. However, I want to make my app compatible on macOS 13 to enable a wider audience.
My current usage of this function is as follows:
func reloadContentViewAfterDelete() {
@Environment(\.openWindow) var openWindow
@Environment(\.dismissWindow) var dismissWindow
dismissWindow(id: "content")
openWindow(id: "content")
}
Images are not appearing on tab bar on visionOS despite it shows up in perfect on iOS.
I tried rendering mode API to make the original image visible, and it is working fine on iOS. But on visionOS the image stays white like masked by the tab bar default content color.
Did anyone achieve solving this problem? I might be able to create my custom ornament to make it look like tab bar, but I think it‘s too much coding to do so.
I am working on a MapView with MapAnnotation on the Map and am having difficulty getting the MapAnnotation to function properly when selected. In my code, I want the MapAnnotation selected to be to the front if it is behind or partially blocked by another annotation. I have tried using a zIndex but this does not appear to work. Below is my MapView code along with a screenshot of the issue. Any help would be greatly appreciated.
struct HospitalMapView: View {
@StateObject var viewModel = HospitalViewModel()
@State private var showSearchView = false
@State private var showListView = false
@State private var selectedTab: Int = 0
var body: some View {
ZStack {
VStack(spacing: 0) {
TopTabView()
// Map that updates the visible hospitals when the user moves or adjusts the map
Map(coordinateRegion: $viewModel.region, interactionModes: .all, annotationItems: viewModel.filteredHospitals) { hospital in
MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: hospital.latitude, longitude: hospital.longitude)) {
RoundedRectangle(cornerRadius: 40)
.fill(viewModel.colorForPercentile(viewModel.calculatePercentile(for: hospital, in: viewModel.filteredHospitals)))
.frame(width: 70, height: 30) // Maintain consistent size, adjust if necessary
.overlay(
Text("$\(Int(hospital.baseCharge / 1000))K")
.foregroundColor(.white)
.bold()
)
.overlay(
RoundedRectangle(cornerRadius: 40)
.stroke(Color.blue, lineWidth: viewModel.selectedHospital == hospital ? 3 : 0)
)
.onTapGesture {
viewModel.selectHospital(hospital)
// Move the selected hospital to the end of the list to bring it to the front
viewModel.bringHospitalToFront(hospital)
viewModel.showBottomSheet = true
}
.scaleEffect(viewModel.selectedHospital == hospital ? 1.1 : 1.0) // Highlight the selected hospital
.zIndex(viewModel.selectedHospital == hospital ? 1 : 0) // Set the zIndex higher for the selected hospital
.animation(.easeInOut, value: viewModel.selectedHospital) // Smooth transition
}
}
.onAppear {
// Initial update of visible hospitals when the map appears
viewModel.updateFilteredHospitals()
}
.onChange(of: viewModel.region) { _ in
// Update the visible hospitals as the user changes the map region
viewModel.updateFilteredHospitals()
}
.edgesIgnoringSafeArea(.all)
}
// Hospital count display hovering over the map
Text("\(viewModel.filteredHospitals.count) Hospitals")
.font(.subheadline)
.foregroundColor(.white)
.padding(8)
.background(Color.black.opacity(0.6))
.cornerRadius(10)
.padding(.top, -315) // Adjust padding to position correctly below the TopTabView
.zIndex(1) // Ensure it's above the map
if let selectedHospital = viewModel.selectedHospital, viewModel.showBottomSheet {
BottomSheetView(isOpen: $viewModel.showBottomSheet, maxHeight: UIScreen.main.bounds.height * 0.3) {
SummaryTabView(selectedHospital: Binding(
get: { selectedHospital },
set: { newValue in viewModel.selectHospital(newValue) }
))
}
.transition(.move(edge: .bottom))
.animation(.spring())
}
}
.safeAreaInset(edge: .bottom) {
BottomTabView(selectedTab: $selectedTab, showListView: $showListView, showSearchView: $showSearchView,
onSearchSelected: {
showSearchView = true
showListView = false
}, onHomeSelected: {
showSearchView = false
showListView = false
}, onListSelected: {
showListView = true
showSearchView = false
})
}
.fullScreenCover(isPresented: $showSearchView) {
SearchView(viewModel: viewModel, showSearchView: $showSearchView, selectedTab: $selectedTab, showListView: $showListView)
}
.fullScreenCover(isPresented: $showListView) {
ListView(selectedTab: $selectedTab, showListView: $showListView, showSearchView: $showSearchView)
.environmentObject(viewModel)
}
.environmentObject(viewModel)
}
}
Is there a SwiftUI version of NSControl.allowsExpansionToolTips? That is, showing a tool tip with the full text when (and only when) a text item is truncated?
Or do I need to use a hosting view to get that behavior?
I've got a Mac Document App using SwiftUI and SwiftData.
All is working well with the models editing, etc.
There's a feature I need to implement, and can't seem to make it work.
From the main window of the app, I need to be able to launch an auxilliary window containing a view-only representation of the model being edited. The required workflow is something like this:
Open a document (SwiftData)
Select a sub-model of the document
Launch the aux window to display the view of the model data (must be in a separate window, because it will be on a different physical display)
Continue making edits to the sub-model, as they are reflected in the other window
So, below is the closest I've been able to come, and it's still not working at all. What happens with this code:
Click on the "Present" button, the encounter-presentation Window opens, but never loads the data model or the view. It's just an empty window.
This is the spot in the main view where the auxiliary window will be launched:
@State
var presenting: Presentation? = nil
var presentingThisEncounter: Bool {
presenting?.encounter.id == encounter.id
}
@Environment(\.openWindow) var openWindow
...
if presentingThisEncounter {
Button(action: { presenting = nil }) {
Label("Stop", systemImage: "stop.fill")
.padding(.horizontal, 4)
}
.preference(key: PresentationPreferenceKey.self, value: presenting)
} else {
Button(action: {
presenting = Presentation(encounter: encounter, display: activeDisplay)
openWindow(id: "encounter-presentation")
}) {
Label("Present", systemImage: "play.fill")
.padding(.horizontal, 4)
}
.preference(key: PresentationPreferenceKey.self, value: nil)
}
Presentation is declared as:
class Presentation: Observable, Equatable {
Here's the contents of the App, where the DocumentGroup & model is instantiated, and the aux window is managed:
@State
var presentation: Presentation?
var body: some Scene {
DocumentGroup(editing: .encounterList, migrationPlan: EncounterListMigrationPlan.self) {
ContentView()
.onPreferenceChange(PresentationPreferenceKey.self) { self.presentation = $0 }
}
Window("Presentation", id: "encounter-presentation") {
VStack {
if let presentation = presentation {
PresentingView(presentation: presentation)
}
}
}
}
And the definition of PresentationPreferenceKey:
struct PresentationPreferenceKey: PreferenceKey {
static var defaultValue: Presentation?
static func reduce(value: inout Presentation?, nextValue: () -> Presentation?) {
value = nextValue()
}
}
I'm building a SwiftUI social photo-sharing app that uses CloudKit, where user profiles (including a CKAsset for profile pictures) are displayed throughout the app. To reduce redundant fetching of profiles across multiple views, I’m trying to implement a cache for the profile CKRecord into a custom model. (Important for handling the CKAsset for a user’s profile picture, ensuring it’s moved from the CloudKit fileURL staging area)
Here's my current approach:
struct UserProfileModel: Identifiable {
let id: String
let displayUsername: String
var profilePicture: UIImage? = nil
}
class UserProfileCache: ObservableObject {
static let shared = UserProfileCache()
@Published var cache: [UserProfileModel] = []
}
Is this a solid approach for caching CKRecords, or is there a more efficient way to structure this for performance and memory management?
I'd appreciate any input or advice on improving this architecture for performance, memory management, and handling profile updates.
Thanks in advance for your help!
We're trying to implement transitions between TabView pages similar to what the Fitness app does on watchOS. As the user swipes or uses the Digital Crown to move between pages, the large rings gauge in the center transitions smoothly to a toolbar item. The code to implement this transition is described in two places in Apple's documentation:
https://developer.apple.com/documentation/watchos-apps/creating-an-intuitive-and-effective-ui-in-watchos-10 (See the section “Provide continuity with persistent elements”)
The WWDC23 session "Design and build apps for watchOS 10", around 9:30
However, copying the code from Apple's documentation doesn't give animation as reliable as what we're seeing in the Fitness app. Any slight reversal of motion causes the transition animation to jump back to the starting state. Has anyone else figured out how to replicate what the Fitness app is doing on watchOS?
I've included our View implementation below. Debug prints show what's going wrong: the page variable decrements immediately the user moves backward by any amount. But somehow, the Fitness app gets around this problem. How?
struct ContentView: View {
@Namespace var namespace
@State var page = 0
var body: some View {
NavigationStack {
TabView(selection: $page) {
globeView
.containerBackground(Color.blue.gradient, for: .tabView)
.navigationTitle("One")
.matchedGeometryEffect(
id: "globe",
in: namespace,
properties: .frame,
isSource: page == 0)
.tag(0)
Text("Page two")
.containerBackground(Color.green.gradient, for: .tabView)
.navigationTitle("Two")
.tag(1)
}
.tabViewStyle(.verticalPage)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
globeView
.matchedGeometryEffect(
id: "globe",
in: namespace,
properties: .frame,
isSource: page == 1)
}
}
}
}
@ViewBuilder
var globeView: some View {
Image(systemName: "globe")
.resizable()
.scaledToFit()
}
}
Thanks for any help!
—Chris
Since I updated my project I'm getting this error
Stored property 'base' of 'Sendable'-conforming struct 'AnyShape' has non-sendable type '(CGRect) -> Path'; this is an error in the Swift 6 language mode
I get this error at that struct, more specifically on the base variable
public struct AnyShape: Shape {
private var base: (CGRect) -> Path
public init<S: Shape>(shape: S) {
base = shape.path(in:)
}
public func path(in rect: CGRect) -> Path {
base(rect)
}
}
I have no idea how to solve this issue, I've been looking on the internet for same issues and get nothing yet
Hi all,
Before updating to iPadOS 18, the Table component in SwiftUI worked as expected, allowing multiple selections using the Shift key and mouse clicks.
However, after the update, this functionality no longer works on iPadOS 18 and macOS 15 (running with Catalyst).
Here’s a simplified version of the code:
@State var selections: Set<String> = []
var body: some View {
Table(devices, selection: $selections) {
// ...
}
}
Is there any workaround for this issue, or has anyone else encountered the same problem?
Thanks!
Dear all, how do I add any extra buttons to the AVPlayer / VideoPlayer menu? I would like to add a button e.g. linking to a particular website.
Thank you!
Hi everyone,
I’m having an issue with a SwiftUI Table inside a Form in a macOS app. When the Form style is set to .grouped, the Table does not resize to the full width of the Form or Sheet. However, when I switch to a .plain style, it resizes correctly.
Here’s a simplified version of my code:
Section(header: Text("Header")) {
Table(data) {
TableColumn("Column 1", value: \.col1)
TableColumn("Column 2", value: \.col2)
// Add more columns as needed
}
.frame(height: 100)
}
}
.formStyle(.grouped) // Issue occurs only with this style
Has anyone else experienced this? Any workarounds or suggestions would be greatly appreciated!
Thanks!
When i use Xcode16 Beta4, I finish some code
for example
@available(iOS 18.0, *)
struct Test001ControlWidget: ControlWidget {
let kind: String = "Test001ControlWidgetKind"
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: kind, content: {
ControlWidgetButton(action: Test001ControlAppIntent(), label: {
HStack {
Image("controlcenter_point")
Text("Test001")
}
})
})
.displayName("Test001")
}
}
@available(iOS 18.0, *)
struct Test001ControlAppIntent: AppIntent {
static let title: LocalizedStringResource = "Open Demo Some Page"
static var isDiscoverable: Bool = false
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult & OpensIntent {
let defaultIntent = OpenURLIntent()
guard let url = URL(string: Test001JumpType.sohuWatchPoint.jumpLink()) else { return .result(opensIntent: defaultIntent) }
return .result(opensIntent: OpenURLIntent(url))
}
}
The icon can be displayed normally and icon type is png.
And deep link also jump normally.(Note: The control widget file target membership are main app and widgetExtension)
But iOS18 RC code is no working and icon show "?"
How do I deal with these issues?
I hope to hear from you soon.
Tks a lot...
Hola, cree una app en swiftui, la version minima de ios 16.2, la desarrolle en xcode 15 sin problema, funcionaba hasta ios 17 sin inconvenientes, actualice a xcode 16 ahora que la ejecuto en ios 18 presenta problemas en varios elementos de la interfaz, por ejemplo cuando toco un boton no desencadena una acción inmediata, tengo que sostener el toque en el boton para que reaccione y asi varios elementos que necesito tocar para llamar una acción, probe la app y funciona correctamente en dispositivos con ios desde el 16.2 al 17, intente modificar el código de los elementos para mejorar el gesto de tocar, pero no funciona, no se porque pasa esto en IOS 18, alguna sugerencia para resolver esto, gracias.
My app uses a temporary singleton to store CKRecords for user profiles, to prevent repeated fetching of profile pics & display usernames during a user's session.
Since iOS 18, after leaving the app in the background for an unspecified period of time & reopening it, the app has started to discard the CKAssets in those 'cached' records.
The records are still there, & the custom fields such as the display username string is still accessible. However the profile pic assets aren't?
This is the code that is displaying the profile picture, could this be something to do with some changes to how CKAssets are given file urls?
if postOwnerRecord != nil, let imageAsset = postOwnerRecord!.object(forKey: "profilePicture") as? CKAsset, let photoData = NSData(contentsOf:imageAsset.fileURL!) {
if let uiImage = UIImage(data: photoData as Data) {
let imageToUse = Image(uiImage: uiImage)
Image(uiImage: imageToUse)
}
}
Expected behavior: CKAssets should persist when resuming the app from the background.
Actual behavior: CKAssets are discarded when reopening the app, but custom fields are still accessible.
Question: Is this related to iOS 18, or am I mishandling how CKAssets are cached or their file URLs? Is there a better approach to caching these assets across app sessions? Any pointers or changes would be appreciated.
I've reviewed iOS 18 release notes but didn't find any clear references to changes with CKAsset handling. Any ideas?
I'm trying to disable Writing Tools for a specific TextField using .writingToolsBehavior(.disabled), but when running the app on my iPhone 16 Pro with Apple Intelligence enabled, I can still use Writing Tools on the text box. I also see no difference with .writingToolsBehavior(.limited).
Is there something I'm doing wrong or is this a bug?
Sample code below:
import SwiftUI
struct ContentView: View {
@State var text = ""
var body: some View {
VStack {
TextField("Enter Text", text: $text)
.writingToolsBehavior(.disabled)
}
.padding()
}
}
#Preview {
ContentView()
}