Try the following code on macOS, and you'll see the marker is added in the wrong place, as the conversion from screen coordinates to map coordinates doesn't work correctly.
The screenCoord value is correct, but reader.convert(screenCoord, from: .local) offsets the resulting coordinate by the height of the content above the map, despite the .local parameter.
struct TestMapView: View {
@State var placeAPin = false
@State var pinLocation :CLLocationCoordinate2D? = nil
@State private var cameraProsition: MapCameraPosition = .camera(
MapCamera(
centerCoordinate: .denver,
distance: 3729,
heading: 92,
pitch: 70
)
)
var body: some View {
VStack {
Text("This is a bug demo.")
Text("If there are other views above the map, the MapProxy doesn't convert the coordinates correctly.")
MapReader { reader in
Map(
position: $cameraProsition,
interactionModes: .all
)
{
if let pl = pinLocation {
Marker("(\(pl.latitude), \(pl.longitude))", coordinate: pl)
}
}
.onTapGesture(perform: { screenCoord in
pinLocation = reader.convert(screenCoord, from: .local)
placeAPin = false
if let pinLocation {
print("tap: screen \(screenCoord), location \(pinLocation)")
}
})
.mapControls{
MapCompass()
MapScaleView()
MapPitchToggle()
}
.mapStyle(.standard(elevation: .automatic))
}
}
}
}
extension CLLocationCoordinate2D {
static var denver = CLLocationCoordinate2D(latitude: 39.742043, longitude: -104.991531)
}
(FB13135770)
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
This is my code in ContentView:
import SwiftUI
import SceneKit
import PlaygroundSupport
struct ContentView: View {
var body: some View {
VStack {
Text("SceneKit with SwiftUI")
.font(.headline)
.padding()
SceneView(
scene: loadScene(),
options: [.autoenablesDefaultLighting, .allowsCameraControl]
)
.frame(width: 400, height: 400)
.border(Color.gray, width: 1)
}
}
}
func loadScene() -> SCNScene? {
if let fileURL = Bundle.main.url(forResource: "a", withExtension: "dae") {
do {
let scene = try SCNScene(url: fileURL, options: [
SCNSceneSource.LoadingOption.checkConsistency: true
])
print("Scene loaded successfully.")
return scene
} catch {
print("Error loading scene: \(error.localizedDescription)")
}
} else {
print("Error: Unable to locate a.dae in Resources.")
}
return nil
}
a.dae file exists in the Resources section of macOS Playground app. And a.dae can be viewed in Xcode.
Console shows: Error loading scene: The operation couldn’t be completed. (Foundation._GenericObjCError error 0.)
Any input is appreciated.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
Swift Student Challenge
Swift Playground
SwiftUI
SceneKit
I am trying out the new TextField selection ability on macOS but it crashes in various different ways with extremely large stack traces. Looks like it is getting into re-entrant function calls.
A similar problem is described on the SwiftUI forums with no responses yet.
Here is my simple example
struct ContentView: View {
@State private var text: String = ""
@State private var selection: TextSelection?
var body: some View {
TextField("Message", text: $text, selection: $selection)
.padding()
}
}
Setting text to a value like "Hallo World" causes an instant crash as soon as you start typing in the TextField.
Setting text empty (as in example above) lets you edit the text but as it crashes as soon as you commit it (press enter).
Any workarounds or fixes?
I recently started exploring the latest version of SwiftUI and encountered an issue while working with TabView and NavigationStack. I downloaded the example code provided by Apple and began making changes to explore new SwiftUI features. However, I noticed that the navigation bar "jumps" or resets when switching between tabs, even in their example implementation.
Here are some changes which I made below in the files:
LibraryView:
.navigationTitle("Library")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(Color("AccentColor"),for: .navigationBar)
WatchNowView:
.navigationTitle("Watch Now")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(Color("AccentColor"),for: .navigationBar)
example code url :- destinationVideo
I suspect the issue arises because each tab bar item has its own NavigationStack. When we set a navigation title for each view, the NavigationStack resets the navigation bar on view appearance, which causes this visual bug.
Thank you!
I recently started exploring the latest version of SwiftUI and came across a issue while working with TabView and NavigationStack. I downloaded Apple’s provided example code and began making changes to explore new SwiftUI changes. i added navigationtitle and toolbarBackground to first two tab. However, I noticed that the navigation bar "jumps" or resets when switching between tabs, even in their own example implementation.
Here’s a simplified version of the example code I was testing:
file name - WatchNowView
.navigationTitle("Watch Now")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(Color("AccentColor"),for: .navigationBar)
file name - LibraryView
.navigationTitle("Library")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(Color("AccentColor"),for: .navigationBar)
Here is a sample code link (provided by Apple developer document) : destination-video
I have attached a gif below demonstrating this issue:
Questions:
Is this behavior expected in the latest version of SwiftUI, or is it a bug in the framework's handling of TabView and NavigationStack?
Is this behavior expected as all tabbar item have their own nativationStack?
Are there any official recommendations for maintaining seamless navigation experiences when using navigationStack and TabView?
This behavior detracts from the otherwise smooth experience SwiftUI aims to provide. If anyone has encountered this issue and found a workaround, I’d greatly appreciate your insights. I hope Apple can review this problem to enhance the usability of SwiftUI. Thank you!
Recently I noticed how my ViewModels aren't deallocating and they end up as a memory leaks. I found something similar in this thread but this is also happening without using @Observation. Check the source code below:
class CellViewModel: Identifiable {
let id = UUID()
var color: Color = Color.red
init() { print("init") }
deinit { print("deinit") }
}
struct CellView: View {
let viewModel: CellViewModel
var body: some View {
ZStack {
Color(viewModel.color)
Text(viewModel.id.uuidString)
}
}
}
@main
struct LeakApp: App {
@State var list = [CellViewModel]()
var body: some Scene {
WindowGroup {
Button("Add") {
list.append(CellViewModel())
}
Button("Remove") {
list = list.dropLast()
}
ScrollView {
LazyVStack {
ForEach(list) { model in
CellView(viewModel: model)
}
}
}
}
}
}
When I tap the Add button twice in the console I will see "init" message twice. So far so good. But then I click the Remove button twice and I don't see any "deinit" messages.
I used the Debug Memory Graph in Xcode and it showed me that two CellViewModel objects are in the memory and they are owned by the CellView and some other objects that I don't know where are they coming from (I assume from SwiftUI internally).
I tried using VStack instead of LazyVStack and that did worked a bit better but still not 100% "deinits" were in the Console.
I tried using weak var
struct CellView: View {
weak var viewModel: CellViewModel?
....
}
but this also helped only partially.
The only way to fully fix this is to have a separate class that holds the list of items and to use weak var viewModel: CellViewModel?. Something like this:
class CellViewModel: Identifiable {
let id = UUID()
var color: Color = Color.red
init() { print("init") }
deinit { print("deinit") }
}
struct CellView: View {
var viewModel: CellViewModel?
var body: some View {
ZStack {
if let viewModel = viewModel {
Color(viewModel.color)
Text(viewModel.id.uuidString)
}
}
}
}
@Observable
class ListViewModel {
var list = [CellViewModel]()
func insert() {
list.append(CellViewModel())
}
func drop() {
list = list.dropLast()
}
}
@main
struct LeakApp: App {
@State var viewModel = ListViewModel()
var body: some Scene {
WindowGroup {
Button("Add") {
viewModel.insert()
}
Button("Remove") {
viewModel.drop()
}
ScrollView {
LazyVStack {
ForEach(viewModel.list) { model in
CellView(viewModel: model)
}
}
}
}
}
}
But this won't work if I want to use @Bindable such as
@Bindable var viewModel: CellViewModel?
I don't understand why SwiftUI doesn't want to release the objects?
Xcode 14.1
Running on iPhone 14 Pro max simulator 16.1
Code...
import SwiftUI
struct ContentView: View {
@State var loggedIn: Bool = false
var body: some View {
switch loggedIn {
case false:
Button("Login") {
loggedIn = true
}
.onAppear {
print("🍏 Login on appear")
}
.onDisappear {
print("🍎 Login on disappear")
}
case true:
TabView {
NavigationView {
Text("Home")
.navigationBarTitle("Home")
.onAppear {
print("🍏 Home on appear")
}
.onDisappear {
print("🍎 Home on disappear")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Logout") {
loggedIn = false
}
}
}
}
.tabItem {
Image(systemName: "house")
Text("Home")
}
NavigationView {
Text("Savings")
.navigationBarTitle("Savings")
.onAppear {
print("🍏 Savings on appear")
}
.onDisappear {
print("🍎 Savings on disappear")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Logout") {
loggedIn = false
}
}
}
}
.tabItem {
Image(systemName: "dollarsign.circle")
Text("Savings")
}
NavigationView {
Text("Profile")
.navigationBarTitle("Profile")
.onAppear {
print("🍏 Profile on appear")
}
.onDisappear {
print("🍎 Profile on disappear")
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Logout") {
loggedIn = false
}
}
}
}
.tabItem {
Image(systemName: "person")
Text("Profile")
}
}
.onAppear {
print("🍏 Tabview on appear")
}
.onDisappear {
print("🍎 Tabview on disappear")
}
}
}
}
Video of bug... https://youtu.be/oLKjRGL2lX0
Example steps...
Launch app
Tap Login
Tap Savings tab
Tap Home tab
Tap Logout
Expected Logs...
🍏 Login on appear
🍏 Tabview on appear
🍏 Home on appear
🍎 Login on disappear
🍏 Savings on appear
🍎 Home on disappear
🍏 Home on appear
🍎 Savings on disappear
🍏 Login on appear
🍎 Home on disappear
🍎 Tabview on disappear
Actual logs...
🍏 Login on appear
🍏 Tabview on appear
🍏 Home on appear
🍎 Login on disappear
🍏 Savings on appear
🍎 Home on disappear
🍏 Home on appear
🍎 Savings on disappear
🍏 Login on appear
🍏 Savings on appear
🍎 Home on disappear
🍎 Savings on disappear
🍎 Tabview on disappear
Error...
10 and 12 in the actual logs should not be there at all.
For each tab that you have visited (that is not the current tab) it will call onAppear and onDisappear for it when the tab view is removed.
Hello,
In my app, I have an onboarding made of multiple steps in a NavigationStack.
I also have a state variable that controls an if else root branch to show either the onboarding NavigationStack or the app content if the onboarding is finished.
I noticed that when I end the onboarding (i.e. I switch to the other part of the if else root branch), the onAppear of the first View in the NavigationStack of the onboarding is called again. I don’t understand why.
Is this a bug?
Thanks,
Axel
enum Step {
case one
case two
case three
case four
}
struct ContentView: View {
@State private var isFinished: Bool = false
@State private var steps: [Step] = []
var body: some View {
if isFinished {
Button("Restart") {
steps = []
isFinished = false
}
} else {
NavigationStack(path: $steps) {
VStack {
Text("Start")
.onAppear { print("onAppear: start") }
Button("Go to step 1") { steps.append(.one) }
}
.navigationDestination(for: Step.self) { step in
switch step {
case .one:
Button("Go to step 2") { steps.append(.two) }
.onAppear { print("onAppear: step 1") }
case .two:
Button("Go to step 3") { steps.append(.three) }
.onAppear { print("onAppear: step 2") }
case .three:
Button("Go to step 4") { steps.append(.four) }
.onAppear { print("onAppear: step 3") }
case .four:
Button("End") {
isFinished = true
}
.onAppear { print("onAppear: end") }
}
}
}
.onAppear { print("onAppear: NavigationStack") }
}
}
}
When running a Mac Catalyst app that uses DocumentGroup, the app fails to display the document content. The document picker works as expected, but creating a new document or opening an existing one results in an empty window. This issue occurs regardless of whether “Optimize for Mac” or “Scale iPad” is selected.
Steps to Reproduce:
1. Download the sample project provided by Apple for building a document-based app in SwiftUI.
2. Delete the macOS version of the project.
3. Add a Mac Catalyst version of the app.
4. In the Mac Catalyst settings, select “Optimize for Mac” (the bug also appears if it is “Scale iPad”).
5. Run the project on macOS.
Expected Result:
The app should correctly display the content of the document when creating or opening it.
Actual Result:
The app opens an empty window when a new document is created or an existing one is opened.
Impact:
We have received multiple 1-star reviews, and our retention has dropped by two-thirds due to this issue.
Environment: Xcode 16.1; macOS 15.1 & 15.2 (on 15.0 it works fine)
Has anyone experienced the same issue? I filed multiple reports so far.
It only seems to happen in the real app I am working on and not within any of the test apps I make.
Its lasted a few Xcode versions. Don't know if this is widespread to the point of having a name?
On iOS you can create a new Lock Screen that contains a bunch of emoji, and they'll get put on the screen in a repeating pattern, like this:
When you have two or more emoji they're placed in alternating patterns, like this:
How do I write something like that? I need to handle up to three emoji, and I need the canvas as large as the device's screen, and it needs to be saved as an image. Thanks!
(I've already written an emojiToImage() extension on String, but it just plonks one massive emoji in the middle of an image, so I'm doing something wrong there.)
Ok… I'm baffled here… this is very strange.
Here is a SwiftUI app:
import SwiftUI
@main struct StepperDemoApp: App {
func onIncrement() {
print(#function)
}
func onDecrement() {
print(#function)
}
var body: some Scene {
WindowGroup {
Stepper {
Text("Stepper")
} onIncrement: {
self.onIncrement()
} onDecrement: {
self.onDecrement()
}
}
}
}
When I run in the app in macOS (Xcode 16.0 (16A242) and macOS 14.6.1 (23G93)), I see some weird behavior from these buttons. My experiment is tapping + + + - - -. Here is what I see printed:
onIncrement()
onIncrement()
onIncrement()
onIncrement()
onDecrement()
What I expected was:
onIncrement()
onIncrement()
onIncrement()
onDecrement()
onDecrement()
onDecrement()
Why is an extra onIncrement being called? And why is one onDecrement dropping on the floor?
Deploying the app to iPhone Simulator does not repro this behavior (I see the six "correct" logs from iPhone Simulator).
The following is my playground code. Any of the apple audio units show the plugin view, however anything else (i.e. kontakt, spitfire, etc.) does not. It does not error, just where the visual is expected is blank.
import AppKit
import PlaygroundSupport
import AudioToolbox
import AVFoundation
import CoreAudioKit
let manager = AVAudioUnitComponentManager.shared()
let description = AudioComponentDescription(componentType: kAudioUnitType_MusicDevice,
componentSubType: 0,
componentManufacturer: 0,
componentFlags: 0,
componentFlagsMask: 0)
var deviceComponents = manager.components(matching: description)
var names = deviceComponents.map{$0.name}
let pluginName: String = "AUSampler" // This works
//let pluginName: String = "Kontakt" // This does not
var plugin = deviceComponents.filter{$0.name.contains(pluginName)}.first!
print("Plugin name: \(plugin.name)")
var customViewController:NSViewController?
AVAudioUnit.instantiate(with: plugin.audioComponentDescription, options: []){avAudioUnit, error in
var ilip = avAudioUnit!.auAudioUnit.isLoadedInProcess
print("Loaded in process: \(ilip)")
guard error == nil else {
print("Error: \(error!.localizedDescription)")
return
}
print("AudioUnit successfully created.")
let audioUnit = avAudioUnit!.auAudioUnit
audioUnit.requestViewController{ vc in
if let viewCtrl = vc {
customViewController = vc
var b = vc?.view.bounds
PlaygroundPage.current.liveView = vc
print("Successfully added view controller.")
}else{
print("Failed to load controller.")
}
}
}
I am trying add Sign in with Apple but when I attempt to capability in my app nothing happens in the list
does apple not able to provide this feature yet in Vision OS or is there any bug or may be ami missing something which does not seems?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = self.parent.viewModel.messages[indexPath.row]
// var cell: RCBaseMessageCell? = tableView.dequeueReusableCell(withIdentifier: String( message.type.rawValue)) as? RCBaseMessageCell
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if #available(iOS 16.0, *) {
cell?.contentConfiguration = UIHostingConfiguration {
Text("123").onTapGesture {
print("123")
}
}
return cell
}
on ios 18.1 onTapGesture sometimes will not callback ,but ios 17 16 is ok,how can i fix it
Keep ScrollView position when adding items on the top using onAppear / onScrollTargeVisibilityChange
Related Post: Keep ScrollView position when adding items on the top
I was trying to implement a message view using ScrollView + LazyVStack. This view requires pagination so I used onScrollTargeVisibilityChange modifier to detect if the first item appears on screen and a new page needs to be loaded. I learnt from the above post that scrollPositon modifier can help keep the scroll position. I tested the method mentioned in that post -- use a button to add new items to the top -- and it worked.
However, when use onScrollTargeVisibilityChange modifier to add items, the view automatically scrolls to the top and cause the following loop:
first item in the list appears on screen --> load and insert more items to the top --> scroll view scrolls to top --> first item appears --> load more data --> scroll to top --> first item ... --> more data... --> top ...
Until it generates the error ScrollTargetVisibilityChange tried to update multiple times per frame.
Here is the simplified code.
struct Item: Identifiable {
var id: UUID = .init()
var content: String
}
struct ScrollViewTest: View {
@State private var items: [Item] = (0...30).map {Item(content:"\($0)")}.reversed()
@State private var itemID: Item.ID?
@State private var page: Int = 0
var body: some View {
ScrollView {
LazyVStack {
ForEach(items) {item in
Text(item.content)
.frame(height: 30)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $itemID)
.defaultScrollAnchor(.bottom)
.onScrollTargetVisibilityChange(idType: Item.ID.self) { onScreenItemIDs in
if onScreenItemIDs.first == items.first?.id {
page += 1
let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
items.insert(contentsOf: newItems.reversed(), at: 0)
}
}
.toolbar {
Button("Add") {
page += 1
let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
items.insert(contentsOf: newItems.reversed(), at: 0)
}
}
}
}
I want to load data while scrolling without the need of pressing any buttons. How can I solve this problem?
Is there a way to implement controls for background audio using ActivityKit like in the Apple Music application? I didn't found anything in your documentation about handling actions like this except deep links, but they're not suitable for this use case
Getting this error:
'Task' is only available in macOS 10.15 or newerSourceKit
LoggerForPreviews.swift(130, 9): Add 'if #available' version check
LoggerForPreviews.swift(129, 24): Add @available attribute to enclosing static method
LoggerForPreviews.swift(5, 20): Add @available attribute to enclosing actor
Does it have something to do with developing in VSCode?
import Foundation
import SwiftUI
// Logger: A concise, globally accessible logging utility for SwiftUI previews
public final actor PreviewLogger: Sendable {
// LogLevel: Defines severity levels for logging
public enum LogLevel: Int, Sendable, CaseIterable {
// Define cases based on LOG_LEVEL_MAP
case trace, debug, verbose, info, notice, warning, error, critical, fatal
// Computed property to get order based on case declaration
private var order: Int {
switch self {
case .trace: return 0
case .debug: return 1
case .verbose: return 2
case .info: return 3
case .notice: return 4
case .warning: return 5
case .error: return 6
case .critical: return 7
case .fatal: return 8
}
}
public var description: String {
// Use capitalized raw value for description
return String(describing: self).uppercased()
}
// Static function to compare log levels
static func >= (lhs: LogLevel, rhs: LogLevel) -> Bool {
return lhs.order >= rhs.order
}
}
// Shared instance for global access
public static let shared = PreviewLogger()
// Current log level
public var logLevelThreshold: LogLevel = .info
private init() {}
// Configure the logger's log level
public func configure(logLevelThreshold: LogLevel) {
self.logLevelThreshold = logLevelThreshold
}
// Helper function to center text within a given width
private func centered(_ text: String, in separator: String) -> String {
let totalLength = separator.count
let textLength = text.count
if textLength >= totalLength {
return text
}
let padding = (totalLength - textLength) / 2
let padString = String(repeating: " ", count: padding)
return padString + text
}
// Main logging function
public func log(
_ message: String,
level: LogLevel = .info,
file: String = #file,
function: String = #function,
line: Int = #line,
callerFile: String? = nil,
callerFunction: String? = nil,
callerLine: Int? = nil
) {
#if DEBUG
guard ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" else {
return
}
guard level >= logLevelThreshold else { return }
let fileName = (file as NSString).lastPathComponent
let cleanFunction = function.replacingOccurrences(of: "(_:file:function:line:)", with: "")
let levelIcon: String
switch level {
case .trace: levelIcon = "🔍"
case .debug: levelIcon = "🛠️"
case .verbose: levelIcon = "📝"
case .info: levelIcon = "ℹ️"
case .notice: levelIcon = "📢"
case .warning: levelIcon = "⚠️"
case .error: levelIcon = "❌"
case .critical: levelIcon = "🚨"
case .fatal: levelIcon = "💀"
}
let header = "[\(levelIcon) \(level.description)]"
let separator =
"· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·"
let finalSeparator =
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
let centeredHeader = centered(header, in: separator)
var output = """
\n\(separator)
\(centeredHeader)
"""
let locationInfo = "📍 \(fileName):\(line) ➜ \(cleanFunction)"
let centeredLocation = centered(locationInfo, in: separator)
output += "\n\(centeredLocation)"
if let callerFile = callerFile,
let callerLine = callerLine
{
let callerFileName = (callerFile as NSString).lastPathComponent
let callerInfo = "📱 Called from: \(callerFileName):\(callerLine)"
let centeredCallerInfo = centered(callerInfo, in: separator)
output += "\n\(centeredCallerInfo)"
}
output += """
\n\(separator)\n\(message)\n\(finalSeparator)
"""
print(output)
#endif
}
// Static Methods
public static func configure(logLevelThreshold: LogLevel) {
Task {
await shared.configure(logLevelThreshold: logLevelThreshold)
}
}
public static func log(
_ message: String,
level: LogLevel = .info,
file: String = #file,
function: String = #function,
line: Int = #line,
callerFile: String? = nil,
callerFunction: String? = nil,
callerLine: Int? = nil
) {
Task {
await shared.log(
message,
level: level,
file: file,
function: function,
line: line,
callerFile: callerFile,
callerFunction: callerFunction,
callerLine: callerLine
)
}
}
}
Hey everyone,
TL;DR
How do I enable a draggable TableView to drop Audio Files into Apple Music / Rekordbox / Finder?
Intro / skip me
I've been dabbling into Swift / SwiftUI for a few weeks now, after roughly a decade of web development.
So far I've been able to piece together many things, but this time I'm stuck for hours with no success using Forums / ChatGPT / Perplexity / Trial and Error.
The struggle
Sometimes the target doesn't accept the dropping at all
sometimes the file data is failed to be read
when the drop succeeds, then only as a stream in apple music
My lack of understanding / where exactly I'm stuck
I think the right way is to use UTType.fileUrl but this is not accepted by other applications.
I don't understand low-level aspects well enough to do things right.
The code
I'm just going to dump everything here, it includes failed / commented out attempts and might give you an Idea of what I'm trying to achieve.
//
// Tracks.swift
// Tuna Family
//
// Created by Jan Wirth on 12/12/24.
//
import SwiftySandboxFileAccess
import Files
import SwiftUI
import TunaApi
struct LegacyTracks: View {
@State var tracks: TunaApi.LoadTracksQuery.Data?
func fetchData() {
print("fetching data")
Network.shared.apollo.fetch(query: TunaApi.LoadTracksQuery()) { result in
switch result {
case .success(let graphQLResult):
self.tracks = graphQLResult.data
case .failure(let error):
print("Failure! Error: \(error)")
}
}
}
@State private var selection = Set<String>()
var body: some View {
Text("Tracks").onAppear{
fetchData()
}
if let tracks = tracks?.track {
Table(of: LoadTracksQuery.Data.Track.self, selection: $selection) {
TableColumn("Title", value: \.title)
} rows : {
ForEach(tracks) { track in
TableRow(track)
.draggable(track)
// .draggable((try? File(path: track.dropped_source?.path ?? "").url) ?? test_audio.url) // This causes a compile-time error
// .draggable(test_audio.url)
// .draggable(DraggableTrack(url: test_audio.url))
// .itemProvider {
// let provider = NSItemProvider()
// if let path = self.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
//
//
// }
// }
//
// provider.register(track)
// return provider
// } // This does not
}
}
.contextMenu(forSelectionType: String.self) { items in
// ...
Button("yoooo") {}
} primaryAction: { items in
print(items)
// This is executed when the row is double clicked
}
} else {
Text("Loading")
}
// }
}
}
//extension Files.File: Transferable {
// public static var transferRepresentation: some TransferRepresentation {
// FileRepresentation(exportedContentType: .audio) { url in
// SentTransferredFile( self.)
// }
// }
//}
struct DraggableTrack: Transferable {
var url: URL
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation (exportedContentType: .fileURL) { item in
SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
}
// FileRepresentation(contentType: .init(filenameExtension: "m4a")) {
// print("file", $0)
// print("Transferring fallback", test_audio.url)
// return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
// }
// importing: { received in
// // let copy = try Self.(source: received.file)
// return Self.init(url: received.file)
// }
// ProxyRepresentation(exporting: \.url.absoluteString)
}
}
extension LoadTracksQuery.Data.Track: @retroactive Identifiable {
}
import UniformTypeIdentifiers
extension LoadTracksQuery.Data.Track: @retroactive Transferable {
// static func getKind() -> UTType {
// var kind: UTType = UTType.item
// if let path = self.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
// if (f.extension == "m4a") {
// kind = UTType.mpeg4Audio
// }
// if (f.extension == "mp3") {
// kind = UTType.mp3
// }
// if (f.extension == "flac") {
// kind = UTType.flac
// }
// if (f.extension == "wav") {
// kind = UTType.wav
// }
//
// }
// }
// return kind
// }
public static var transferRepresentation: some TransferRepresentation {
ProxyRepresentation {
$0.dropped_source?.path ?? ""
}
FileRepresentation(exportedContentType: .fileURL) { <#Transferable#> in
SentTransferredFile(<#T##file: URL##URL#>, allowAccessingOriginalFile: <#T##Bool#>)
}
// FileRepresentation(contentType: .fileURL) {
// print("file", $0)
// if let path = $0.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
// return SentTransferredFile(f.url, allowAccessingOriginalFile: true)
// }
// }
// print("Transferring fallback", test_audio.url)
// return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
// }
// importing: { received in
// // let copy = try Self.(source: received.file)
// return Self.init(_fieldData: received.file)
// }
// ProxyRepresentation(exporting: \.title)
}
}
On an iPad or iPhone running iPadOS / iOS 18.2 (built with Xcode 16.2), run the WritingApp sample code from https://developer.apple.com/documentation/SwiftUI/Building-a-document-based-app-with-SwiftUI from WWDC24
Then add the following struct to the project:
struct NavigationBarToolbar: ToolbarContent {
var body: some ToolbarContent {
ToolbarItem(placement: .secondaryAction) {
Button("Button 1", systemImage: "1.circle") { }
}
ToolbarItem(placement: .secondaryAction) {
Button("Button 2", systemImage: "2.circle") { }
}
ToolbarItem(placement: .secondaryAction) {
Button("Button 3", systemImage: "3.circle") { }
}
ToolbarItem(placement: .secondaryAction) {
Button("Button 4", systemImage: "4.circle") { }
}
ToolbarItem(placement: .secondaryAction) {
Button("Button 5", systemImage: "5.circle") { }
}
}
}
Comment out the original toolbar in the sample project and replace with:
.toolbar(content: NavigationBarToolbar.init)
Run the project and open or create a document
Click on the TitleMenu and choose Rename, in order to rename the file
Type in a new name and press Enter.
Notice how the items of the toolbar disappear
——
This issue has been submitted as feedback with number FB16100225
This issue is linked to the following feedbacks:
FB14855728
FB14855668
FB14849205
FB12343963
FB15164292