I'm getting the following error in my SwiftUI code:
"Main actor-isolated property 'avatarImage' can not be referenced from a Sendable closure"
I don't understand how to fix it.
This happens in the following code:
You can copy-paste this into an empty project and make sure to have Swift 6 enabled under the Build Settings > Swift Language Version
import PhotosUI
import SwiftUI
public struct ContentView: View {
@State private var avatarItem: PhotosPickerItem?
@State private var avatarImage: Image?
@State private var avatarData: Data?
public var body: some View {
VStack(spacing: 30) {
VStack(alignment: .center) {
PhotosPicker(selection: $avatarItem, matching: .images) {
if let avatarImage {
avatarImage
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.foregroundColor(.gray)
.background(.white)
.clipShape(Circle())
.opacity(0.75)
.overlay {
Image(systemName: "pencil")
.font(.title)
.shadow(radius: 5)
}
} else {
Image(systemName: "person.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 100)
.foregroundColor(.gray)
.background(.white)
.clipShape(Circle())
.opacity(0.75)
.overlay {
Image(systemName: "pencil")
.font(.title)
.shadow(radius: 5)
}
}
}
}
}
.onChange(of: avatarItem) {
Task {
if let data = try? await avatarItem?.loadTransferable(
type: Data.self
) {
if let processed = processImage(data: data) {
avatarImage = processed.image
avatarData = processed.data
} else {
}
}
}
}
}
private func processImage(data: Data) -> (image: Image?, data: Data?)? {
guard let uiImage = UIImage(data: data)?.preparingForDisplay() else {
return nil
}
// Check original size
let sizeInMB = Double(data.count) / (1024 * 1024)
// If image is larger than 1MB, compress it
if sizeInMB > 1.0 {
guard let compressedData = uiImage.compress() else { return nil }
return (Image(uiImage: uiImage), compressedData)
}
return (Image(uiImage: uiImage), data)
}
}
#Preview {
ContentView()
}
public extension UIImage {
func compress(to maxSizeInMB: Double = 1.0) -> Data? {
let maxSizeInBytes = Int(
maxSizeInMB * 1024 * 1024
) // Convert MB to bytes
var compression: CGFloat = 1.0
let step: CGFloat = 0.1
var imageData = jpegData(compressionQuality: compression)
while (imageData?.count ?? 0) > maxSizeInBytes, compression > 0 {
compression -= step
imageData = jpegData(compressionQuality: compression)
}
return imageData
}
}
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
❌ Could not find email_ai.py in the app bundle. Available files: []
The error above is what I’m encountering.
I’ve placed the referenced file both in the project directory and inside the app. However, every time I remove and reinsert the file into the folder within the app, it prompts me to designate the targets—I select all, but this doesn’t resolve the issue.
I’m unsure how to properly reference the file so that it is recognised and included in the bundle. Any guidance would be greatly appreciated.
this is my build phase:
#!/bin/sh
set -x # Prints each command before running it (for debugging)
pwd # Shows the current working directory
echo "$SRCROOT" # Shows what Xcode thinks is the project root
ls -l "$SRCROOT/EmailAssistant/EmailAssistant/PythonScripts" # Lists files in the script folder
export PYTHONPATH="/Users/caesar/.pyenv/versions/3.11.6/bin"
/Users/caesar/.pyenv/versions/3.11.6/bin/python3 "$SRCROOT/EmailAssistant/EmailAssistant/PythonScripts/email_ai.py"
echo "Script completed."
As you can see in the screenshot, the verification popups that appear when making a StoreKit purchase cut off the buttons. When typing the code into the input field, the window will also flicker and stutter with random view refreshes. Is this something I can configure/change? It's not a very pleasant experience for making an in app purchase.
Given a sheet with [.medium] detents, that contains a native ColorPicker in SwiftUI:
struct SheetView: View {
@State var color: Color = .white
var body: some View {
ColorPicker(
"Color",
selection: $color,
supportsOpacity: false
)
.padding()
}
}
struct ContentView: View {
@State var isSheetOpen = false
var body: some View {
Button("Open Sheet") {
isSheetOpen = true
}
.sheet(isPresented: $isSheetOpen) {
SheetView()
.presentationDetents([.medium])
}
}
}
When I tap the ColorPicker's color indicator button, it presents the color picker sheet with a layout glitch.
During the color picker presentation animation, the original sheet (SheetView) is rapidly pushed up and back down.
It is a wild guess but I think it has to do something with keyboard avoidance.
Unfortunately, this makes it impossible to use the picker in my app....
I tried to create a Text View using attributedString. I want to set the line height using paragraphStyle and return the Text, but paragraphStyle is not being applied. Why is that?
extension Text {
init?(_ content: String, font: StyleType, color: Color = .ppBlack) {
var attributedString = AttributedString(content)
attributedString.font = Font.custom(font.fontWeight, fixedSize: font.fontSize)
attributedString.foregroundColor = color
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = 16
paragraphStyle.maximumLineHeight = 16
paragraphStyle.lineSpacing = 0
attributedString.mergeAttributes(.init([.paragraphStyle: paragraphStyle]))
self = Text(attributedString)
}
}
I am following this example to create a stereoscopic image: https://developer.apple.com/documentation/visionos/creating-stereoscopic-image-in-visionos
I would also like to add corner radius to the stereoscopic RealityView. With ordinary SwiftUI views, we typically just use .clipShape(RoundedRectangle(cornerRadius: 32)):
struct StereoImage: View {
var body: some View {
let spacing: CGFloat = 10.0
let padding: CGFloat = 40.0
VStack(spacing: spacing) {
Text("Stereoscopic Image Example")
.font(.largeTitle)
RealityView { content in
let creator = StereoImageCreator()
guard let entity = await creator.createImageEntity() else {
print("Failed to create the stereoscopic image entity.")
return
}
content.add(entity)
}
.frame(depth: .zero)
}
.padding(padding)
.clipShape(RoundedRectangle(cornerRadius: 32)) // <= HERE!
}
}
This doesn't seem to actually clip the RealityView shown in the sample above. I am guessing this is due to the fact that the box in the RealityView has a non-zero z scale, which means it isn't on the same "layer" as its SwiftUI containers, and thus isn't clipped by the modifiers apply to the containers.
How can I properly apply a clipshape to RealityViews like this? Thanks!
I'm trying to create a List that allows multiple selection. Each row can be edited but the issue is that since there's a tap gesture on the Text element, the list is unable to select the item.
Here's some code:
import SwiftUI
struct Person: Identifiable {
let id: UUID
let name: String
init(_ name: String) {
self.id = UUID()
self.name = name
}
}
struct ContentView: View {
@State private var persons = [Person("Peter"), Person("Jack"), Person("Sophia"), Person("Helen")]
@State private var selectedPersons = Set<Person.ID>()
var body: some View {
VStack {
List(selection: $selectedPersons) {
ForEach(persons) { person in
PersonView(person: person, selection: $selectedPersons) { newValue in
// ...
}
}
}
}
.padding()
}
}
struct PersonView: View {
var person: Person
@Binding var selection: Set<Person.ID>
var onCommit: (String) -> Void = { newValue in }
@State private var isEditing = false
@State private var newValue = ""
@FocusState private var isInputActive: Bool
var body: some View {
if isEditing {
TextField("", text: $newValue, onCommit: {
onCommit(newValue)
isEditing = false
})
.focused($isInputActive)
.labelsHidden()
}
else {
Text(person.name)
.onTapGesture {
if selection.contains(person.id), selection.count == 1 {
newValue = person.name
isEditing = true
isInputActive = true
}
}
}
}
}
Right now, you need to tap on the row anywhere but on the text to select it. Then, if you tap on the text it'll go in edit mode.
Is there a way to let the list do its selection? I tried wrapping the tap gesture in simultaneousGesture but that didn't work.
Thanks!
Use Case
If you have a ContentView that displays a pausable view based on a
@State private var presentSheet = false
property that is also used to present a
.sheet(isPresented: $presentSheet)
if:
the property is sent to the PausableView(isPaused: presentSheet) as a normal property, the body of the ContentView and the body of the sheet is being redrawn when the sheet is dismissed
the property is sent to the PausableView(isPaused: $presentSheet) as a @Binding, the body of the ContentView and the body of the sheet is NOT redrawn when the sheet is dismissed
Is this normal behavior?
The ContentView body makes sense to change, but is the sheet's body also supposed to be redrawn when the sheet is not presenting anymore after dismiss?
Sample Project
A sample project created in Xcode 13 is available here: https://github.com/clns/SwiftUI-sheet-redraw-on-dismiss. I noticed the same behavior on iOS 14 and iOS 15.
There are also 2 animated gifs showing the 2 different behaviors in the GitHub project.
The relevant code is in ContentView.swift:
import SwiftUI
struct DismissingView: View {
@Binding var isPresented: Bool
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
} else {
print("DismissingView: body draw")
}
return VStack {
Button("Dismiss") { isPresented.toggle() }
Text("Dismissing Sheet").padding()
}.background(Color.white)
}
}
struct PausableView: View {
var isPaused: Bool
// @Binding var isPaused: Bool
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State private var counter = 0
var body: some View {
Text("Elapsed seconds: \(counter)")
.onReceive(timer) { _ in
counter += isPaused ? 0 : 1
}
}
}
struct ContentView: View {
@State private var presentSheet = false
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
} else {
print("ContentView: body draw")
}
return VStack{
Button("Show Sheet") { presentSheet.toggle() }
Text("The ContentView's body along with the .sheet() is being redrawn immediately after dismiss, if the @State property `presentSheet` is used anywhere else in the view - e.g. passed to `PausableView(isPaused:presentSheet)`.\n\nBut if the property is passed as a @Binding to `PausableView(isPaused:$presentSheet)`, the ContentView's body is not redrawn.").padding()
PausableView(isPaused: presentSheet)
// PausableView(isPaused: $presentSheet)
}
.sheet(isPresented: $presentSheet) {
DismissingView(isPresented: $presentSheet)
.background(BackgroundClearView()) // to see what's happening under the sheet
}
}
}
I am on Xcode 16.2 and running a simulator for iOS 18.2. Previously, I was on Xcode 15.x and running iOS 17.4 sims. This problem did not occur for me on iOS 17.4. Sample code is as follows:
import SwiftUI
import PhotosUI
struct ContentView: View {
@StateObject var imagePicker2 = ImagePicker()
var body: some View {
ScrollView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
.background(Color.orange)
.padding(.bottom, 75)
PhotosPicker(selection: $imagePicker2.imageSelection, matching: .images, photoLibrary: .shared()) {
Label("", systemImage: "photo")
}
.font(.system(size: 55))
.padding(.bottom, 55)
if let image = imagePicker2.image {
HStack {
image
.resizable()
.frame(width:75, height:75)
.scaledToFit()
.overlay(Rectangle().stroke(Color.teal, lineWidth: 2))
}
}
}
.padding()
}
}
}
import SwiftUI
import PhotosUI
@MainActor
class ImagePicker: ObservableObject {
@Published var unableToLoad: Bool = false
@Published var image: Image?
@Published var myUIImage: UIImage?
@Published var imageSelection: PhotosPickerItem? {
didSet {
unableToLoad = false
if let imageSelection {
//.. try to convert photosPickerItem imageSelection into a uiImage
Task {
try await setImage(from: imageSelection)
}
}
}
}
func setImage(from imageSelection: PhotosPickerItem?) async throws {
do {
if let data = try await imageSelection?.loadTransferable(type: Data.self) {
print("got image data")
if let uiImage = UIImage(data: data) {
print("converted to uiImage")
self.image = Image(uiImage: uiImage)
self.myUIImage = uiImage
}
}
} catch {
print(error.localizedDescription)
unableToLoad = true
}
}
}
The image loads on the UI but I get "[ERROR] Could not create a bookmark: NSError: Cocoa 4097 "connection to service named com.apple.FileProvider" in the log every time I choose a new photo. So far, I haven't had an actual crash but others have indicated that depending on what they're doing code-wise, that some have crashed. Is this an iOS 18.x bug? Thoughts?
I have a List with draggable items. According to this thread (https://developer.apple.com/forums/thread/664469) I had to use .itemProvider instead of .onDrag, because otherwise the selection of the list will not work anymore.
The items in my list refer to a file URL. So the dragging allowed to copy the files to the destination of the drag & drop. Therefore I used this code
.itemProvider {
let url = ....... // get the url with an internal function
return NSItemProvider(object: url as NSURL)
}
Since the update to macOS 15.1 this way isn't working anymore. It just happens nothing.
I also tried to use
.itemProvider {
let url = ....
return NSItemProvider(contentsOf: url) ?? NSItemProvider(object: url as NSURL)
}
but this doesn't work too.
The same way with .onDrag works btw.
.onDrag {
let url = ....... // get the url with an internal function
return NSItemProvider(object: url as NSURL)
}
but as I wrote, this will break the possibility to select or to use the primaryAction of the .contextMenu.
Is this a bug? Or is my approach wrong and is there an alternative?
Hi,
On visionOS to manage entity rotation we can rely on RotateGesture3D. We can even with the constrainedToAxis parameter authorize only rotation on an x, y or z axis or even make combinations.
What I want to know is if it is possible to constrain the rotation on axis automatically.
Let me explain, the functionality that I would like to implement is to constrain the rotation on an axis only once the user has started his gesture. The initial gesture the user makes should let us know which axis they want to rotate on.
This would be equivalent to activating a constraint automatically on one of the axes, as if we were defining the gesture on one of the axes.
RotateGesture3D(constrainedToAxis: .x)
RotateGesture3D(constrainedToAxis: .y)
RotateGesture3D(constrainedToAxis: .z)
Is it possible to do this?
If so, what would be the best way to do it?
A code example would be greatly appreciated.
Regards
Tof
In Xcode 16.0 and 16.1, it was clear how @Entry macro works from the generated code. If you explicitly specify the type, then defaultValue is a computed property, if you do not specify the type, then a stored property.
In Xcode 16.2, @__EntryDefaultValue has been added to the generated code, which Xcode does not want to expand. Visually, it seems that a stored property is generated, but the behavior shows that as a result we have a computed property, and for both options: with an explicit type and without an explicit type.
So the question is: what does this @__EntryDefaultValue macro generate and is the result a bug? Or was it a bug in previous versions of Xcode?
On macOS, we have didMountNotification but there doesn't seem to be an equivalent for iOS. Is there a way to be notified when a volume is mounted on iOS? I would like to use it in my iOS app I'm currently porting from macOS, which starts a synchronization from the volume (which has been previously selected in a NSOpenPanel) as soon as it's mounted.
I have a macOS app made with SwiftUI where I want to show a list of data in a tabular fashion. SwiftUI Table seems to be the only built-in component that can do this.
I would like to let the user size the columns and have their widths restored when the app is relaunched. I can find no documentation on how to do this and it does not seem to be saved and restored automatically.
I can find no way to listen for changes in the column widths when the user resizes and no way to set the size from code.
For a macOS app it seems that the only way to set the width of a column is to use e.g. .width(min: 200, max: 200). This in effect disables resizing of the column. It seems that idealSize is totally ignored on macOS.
Any suggestions?
When I switched to observable, I noticed a strange behavior of the ViewModel. The ViewModel is created 3x times. And my question is:
How to properly initialize the ViewModel via state?
Below is a minimal example with log output:
ViewModel INIT : EBBB2C41
ViewModel INIT : D8E490DA
ViewModel INIT : 54407300
ViewModel DEINIT: D8E490DA
@Observable
final class ViewModel {
@ObservationIgnored let idd: UUID
init() {
idd = UUID()
print("ViewModel INIT : \(idd.uuidString.prefix(8))")
}
deinit {
print("ViewModel DEINIT: \(idd.uuidString.prefix(8))")
}
}
struct SimpleView: View {
@Environment(ViewModel.self) private var viewModel
var body: some View {
@Bindable var viewModel = viewModel
Text("SimpleView: \(viewModel.idd.uuidString.prefix(8))")
}
}
struct ContentView: View {
@State private var viewModel = ViewModel()
var body: some View {
SimpleView()
.environment(mainViewModel)
}
}
Here is the reproducible codes:
struct JumpView: View {
var body: some View {
NavigationStack {
TabView {
Text("Jump")
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Done") {}
}
}
}
}
}
}
Run directly in real apple watch device in watchOS 10.0+ (do not debug connecting with Xcode).
When raise your wrist the ToolBar Button will jump weirdly.
Hi everyone! I'm thrilled to share that I'm conducting a field research as part of my final university project, focused on iOS architecture.
The goal is to dive deeper into the best practices, challenges, and trends in the iOS development world. To make this research truly impactful, I need your help!
If you're an iOS developer, I’d love it if you could take a few minutes to answer a short survey. Your insights and experiences will be invaluable for my research, and I greatly appreciate your
support!
Here is the link:
https://docs.google.com/forms/d/e/1FAIpQLSdf9cacfA7my1hnlazyl7uJraa2oTsQ7dJBWvFtZ_4vbYenRA/viewform?usp=send_form
Thank you so much in advance for helping me out—feel free to share this post with others who might also be interested. Let’s build something amazing together! 💡✨
Hi everyone,
I believe this should be a simple and expected default behavior in a real-world app, but I’m unable to make it work:
1. I have a View (a screen/page in this case) that calls an endpoint using async/await.
2. If the endpoint hasn’t finished, but I navigate forward to a DetailView, I want the endpoint to continue fetching data (i.e., inside the @StateObject ViewModel that the View owns). This way, when I go back, the View will have refreshed with the fetched data once it completes.
3. If the endpoint hasn’t finished and I navigate back to the previous screen, I want it to be canceled, and the @StateObject ViewModel should be deinitialized.
I can achieve 1 and 3 using the .task modifier, since it automatically cancels the asynchronous task when the view disappears:
view
.task { await vm.getData() }
I can achieve 1 and 2 using a structured Task in the View (or in the ViewModel, its the same behavior), for example:
.onFirstAppearOnly {
Task { away vm.getData() }
}
onFirstAppearOnly is a custom modifier that I have for calling onAppear only once in view lifecycle. Just to clarify, dont think that part is important for the purpose of the example
But the question is: How can I achieve all three behaviors? Is this really such an unusual requirement?
My minimum deployment target is iOS 15, and I’m using NavigationView + NavigationLink. However, I have also tried using NavigationStack + NavigationPath and still couldn’t get it to work.
Any help would be much appreciated.
Thank you, folks!
Hello!
I'm trying to set a UiRefreshControl.tintColor:
.onAppear {
UIRefreshControl.appearance().tintColor = UIColor.systemBlue
}
But instead of
I get
The color in the second picture is a high contrast version of the first one. I can't understand why it works this way.
I also tried the following.
UIRefreshControl.appearance().tintColor = UIColor(red: 0, green: 0.478, blue: 1, alpha: 1) // doesn't work
UIRefreshControl.appearance().tintColor = UIColor(named: "RefreshControlColor") // doesn't work, here set "High contrast" on and indicated Universal.systemBlueColor
Perhaps I missed something?
I have been playing around with the new AsyncImage Api in SwiftUI
I am using the initialiser that passes in a closure with the AsyncImagePhase, to view why an image may not load, when I looked at the error that is passed in if the phase is failure, the localised description of the error is "Cancelled" but this is happening before the view is being displayed.
I am loading these images in a list, I imagine I am probably doing something which is causing the system to decide to cancel the loading, but I cannot see what.
Are there any tips to investigate this further?