Ah, I found out, that it seems to be a bug (the search was long!!).
I could implement the Transferable protocol successfully and I can drag and drop the file to the Finder. BUT: It's not working, if you put the view with the .draggable into a List (with ForEach).
Any ideas?
EDIT:
Here a working example:
struct Document: Transferable {
let name: String
let url: URL
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .data) { document in
SentTransferredFile(document.url)
} importing: { received in
let tmpFileURL = FileManager.default.temporaryDirectory.appending(path: received.file.lastPathComponent)
try FileManager.default.copyItem(at: received.file, to: tmpFileURL)
return Self.init(name: "", url: tmpFileURL)
}
.suggestedFileName { document in
document.url.lastPathComponent
}
}
}
struct ContentView: View {
let document = Document(name: "Test-File", url: FileManager.default.homeDirectoryForCurrentUser.appending(path: "Desktop/test.txt"))
var body: some View {
VStack {
Text("file")
.draggable(document)
}
.padding()
}
}
But this will not work:
var body: some View {
VStack {
List {
Text("file")
.draggable(document)
}
}
.padding()
}
I can see, that dragging works, but if I drop the file into the Finder, just nothing happens.
Post
Replies
Boosts
Views
Activity
Sorry, that I didn't add this information:
I am dragging from my app to another app like Finder or Mail. My original code with .itemProvider exported a NSURL, then Finder copied the file to the drop location and Mail used the file as an attachment. Using now .itemProvider it just happens nothing in Finder or Mail.
So what to use now from this? https://developer.apple.com/documentation/coretransferable/choosing-a-transfer-representation-for-a-model-type
I even tried this workaround: https://nonstrict.eu/blog/2023/transferable-drag-drop-fails-with-only-FileRepresentation/
Yes, I tried to use draggable, but it just happens nothing. But maybe I don't understand correctly how to implement it.
My model Document conforms to Codable:
List(selection: self.$selectedDocument) {
ForEach(self.documents) { document in
DocumentView(document)
.draggable(document)
}
and
extension Document: @retroactive Transferable {
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .data) { document in
return SentTransferredFile(document.url)
}
}
}
Sorry to bother again, but please: Any reaction to this? The bug still exists in 15.1. Am I the only one experiencing this bug?
Maybe it has to do sth. with this change?
Fixed: List on macOS 15 does not use NSTableView for showing non-outline content anymore. (77273697)
I will send my whole code at the end of this post. But if you test it, I do the following. I just compile my app and start it. I then scroll down to "section 14" Then I click on "element 4" and the scroll position will randomly change.
It will look like this:
With Instruments I see internal stuff like this when selecting:
[NSTableRowHeightData computeTotalRowsSpan]
or
[NSTableRowHeightData _estimatedRowAtOffset:]
This is my code, anyone can try.
import SwiftUI
struct ListElement: Identifiable {
var id = UUID()
var section: String
var entries: [Entry]
}
struct Entry: Identifiable, Hashable {
var id = UUID()
var text: String
}
struct ContentView: View {
let listElements = [
ListElement(
section: "Section 1",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 2",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 3",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 4",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 5",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 6",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 7",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 8",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 9",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 10",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 11",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 12",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 13",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 14",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 15",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 16",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
ListElement(
section: "Section 17",
entries: [
Entry(text: "Element 1"),
Entry(text: "Element 2"),
Entry(text: "Element 3"),
Entry(text: "Element 4"),
Entry(text: "Element 5"),
Entry(text: "Element 6"),
Entry(text: "Element 7"),
]),
]
@State var selected: UUID?
var body: some View {
List(selection: self.$selected) {
ForEach(self.listElements) { element in
Section {
ForEach(element.entries) { entry in
EntryView(entry: entry)
}
} header: {
Text(element.section)
}
}
}
}
}
struct EntryView: View {
let entry: Entry
var body: some View {
VStack(alignment: .leading, spacing: 2) {
Text(entry.text)
Text("another line")
}
}
}
#Preview {
ContentView()
}
Could you reproduce this bug? Do you need any additional informations? I couldn't find a workaround for this bug.
I didn't change any line of code and I didn't have the problem with Sonoma.
Thank you very much for your answer. Did you saw the video I made from the behaviour? It's interesting, that you couldn't reproduce. Please scroll nearly to the bottom and then select an item.
In my other project I could solve the problem after deleting everything what was displayed in the list and I only had one Text element. But that surely cannot be the solution ;)
I just filed a bug (FB15269193). It happens only in very long lists and only when scrolling down the first time. List seems to recalculate the heights of the cells and there must be a bug. I hope, that Apple will fix this in the next release.
@ugglaguggla : Do you experience the same behaviour in the Xcode Preview? I only have the issue when using the compiled version.
I have exactly the same issue. The "_hitTestForEvent" method only takes 38,3 %, but the "_routeMouseMovedEvent" has 55,8 % (I am using the Magic Mouse instead of the touch pad).
For me it seems to be a bug in SwiftUI.
Thank you very much. This really did bring a lot of light into my question.
I took a look on NSFilePresenter and at least I now can easily find out, that the file is changed and it seems to work even if the target application works with a file copy.
But yes, the main problem still will be, that apps can just load the file into memory and then close the file descriptor. Then there is no chance to know, if the file is still opened, except that I know, in which way the application creates those file copys for safe-save.
Thank you very much for your detailed answer!
Your're right, I just tested it with a simple .txt-file. lsof only checks, if there is an open file descriptor, but of course, there is none, if the file is completely read to the memory and then closed. It was true for pdf files opened by Preview (I just tested them so far).
Wow, that completely changes my plans, because it then seems, that there is no possibility to know, if my file is opened by another application or not. In the case of a txt-file it even would lead to the opposite, as then I would get notified, that the file was opened and then immediately closed.
Anyways, I could maybe implement it for those files (like pdf or other files), where the application keeps the file descriptor opened. So independently to my use case, is there any API, with which I get notified, when the file (desriptor) is opened or closed?
EDIT: After reading your linked topic, it seems to be only possible with Endpoint Security system extension?
@den73: Nice solution and it seems to work, at least partly. Do you also experience the issue, that sometimes on the first few clicks the element is not selected correctly with the blue selection? For me it happens, that there is a grey selection.
EDIT
Your solution also seems to break the behaviour, that you can move the selection while click and hold, then move the mouse over the items.
Unbelievable, that there is still no solution from Apple.
@Jim Dovey: Thank for that good explanation. I had this problem as well more then once and I also found out, that SwiftUI completely rerenders the whole UI altough only one property is changed. The example of tom.king can be easily splitted up into @State so you can avoid this problem.
But how to do with sth. more complex like this?
class ViewModel: ObservableObject {
		@Published var documents: [Document]
		struct Document {
				var fileName: String = ""
				var documentName: String = ""
				var someOtherInfo = 4
		}
		init(fieldCount: Int) {
				self.documents = Array<Document>.init(repeating: Document(), count: fieldCount)
		}
}
struct ContentView: View {
		@ObservedObject var viewModel = ViewModel(fieldCount: 20)
		var body: some View {
				ScrollView(.vertical) {
						VStack(alignment: .leading) {
								ForEach(self.viewModel.documents.indices) { index in
										DocumentView(viewModel: self.viewModel, index: index)
								}
						}
				}
		}
}
struct DocumentView: View {
		@ObservedObject var viewModel: ViewModel
		var index: Int
		var body: some View {
				VStack(alignment: .leading) {
						Text("\(index)")
						HStack {
								Text("Filename:")
										.frame(width: 200)
								TextField("", text: self.$viewModel.documents[index].fileName)
										.textFieldStyle(RoundedBorderTextFieldStyle())
						}
						HStack {
								Text("DocumentName:")
										.frame(width: 200)
								TextField("", text: self.$viewModel.documents[index].documentName)
										.textFieldStyle(RoundedBorderTextFieldStyle())
						}
				}
				.padding()
				.background(Rectangle().fill(Color(#colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1))).cornerRadius(15))
		}
}
I have the same problem with swift-nio and swift-nio-ssl. For me this way doesn't work, I tried several combinations... I think a problem could be, that for example CNIOBoringSSL is not a Swift package, it doesn't have a Package.swift. Any advice how to solve this problems when using swift-nio and swift-nio-ssl?
This has nothing to do with SwiftUI. SwiftUI renders your controls in your macOS or iOS-application. You need to think about how you present your values in a pdf. You need to create the pdf in your Swift code. For this you can choose different ways, for example you can choose a framework for that (i. e. PDFKit from Apple) or you create an HTML-file and render this to a pdf. You find a lot of stuff if you google for "Swift create PDF"