Core Transferable

RSS for tag

Declare a transfer representation for your model types to participate in system sharing and data transfer operations.

Core Transferable Documentation

Posts under Core Transferable tag

15 Posts
Sort by:
Post marked as solved
2 Replies
382 Views
I am trying to use a ShareLink to share multiple transferrable, and I cannot work out which of the initialisers to use - none seem to work. Assuming I have a transferable that takes some data and processes it asynchronously: struct MyTransferable: some Transferable { let renderer: Renderer static var transferRepresentation: some TransferRepresentation { DataRepresentation(exportedContentType: .png) { transferable in let image = try await transferable.render.render() return image } } } In SwiftUI, I want to share N of these transferables. For example: struct MyView: View { private var transferables: [any Transferable] { [MyTransferable(), MyTransferable()] } var body: some View { ShareLink("Renders", items: transferables) } } But the compiler doesn't like this - it complains with "No exact matches in call to initializer". Is this possible? I feel like it should be?
Posted
by Matt Cox.
Last updated
.
Post not yet marked as solved
1 Replies
237 Views
I am currently working on a SwiftUI project and encountering an issue with the .copyable(_:) modifier. I want to copy the currently selected items in a List, and while using .copyable(_:) works outside of navigation components, it doesn't seem to have any effect when used within NavigationSplitView or NavigationStack. Has anyone successfully implemented copying functionality within a navigation structure using .copyable(_:)? import SwiftUI struct ContentView: View { var body: some View { NavigationSplitView { List(0..<10) { Text("row \($0)") } } detail: { CopyableList() } } } struct CopyableList: View { let strings = ["Alpha", "Beta", "Gamma"] @State private var selection: Set<String> = [] var body: some View { List(strings, id: \.self, selection: $selection) { Text($0) } .copyable(Array(selection)) } }
Posted
by oden-oden.
Last updated
.
Post not yet marked as solved
0 Replies
781 Views
Hello! I'm working on an app that generates CSV files in memory and allows users to export them through a ShareLink. I am using a custom UTType for my CSV files as .commaSeparatedText exports a .txt file, and a custom UTType was proposed as a workaround here: https://www.hackingwithswift.com/forums/swiftui/sharelink-problem-with-csv-file/21194. The app works on a development build, albeit with a lot of entitlement and sandboxing errors, but fails in production (sideloaded archive). Development errors are as follow: Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}> (501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.} Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} The additional production error I'm encountering is the following: Type "com.sunkensplashstudios.VRCRoboScout.csv" was expected to be declared and exported in the Info.plist of App.app, but it was not found. I have, to the best of my knowledge, declared these data types properly: Relevant code is below: extension UTType { static var CSVData: UTType { UTType(exportedAs: "com.sunkensplashstudios.VRCRoboScout.csv") } } struct CSVData: Transferable { var csv_string: String static var transferRepresentation: some TransferRepresentation { DataRepresentation(exportedContentType: .CSVData) { csv in csv.csv_string.data(using: .utf8)! } } } ShareLink(item: CSVData(csv_string: csv_string), preview: SharePreview("VRC RoboScout Scouting Data.csv", image: Image(systemName: "tablecells"))) { Text("Download").padding(10) .background(settings.accentColor()) .foregroundColor(.white) .cornerRadius(20) } Any ideas?
Posted Last updated
.
Post not yet marked as solved
3 Replies
1.5k Views
Hi everyone. I trying to implement some drag and drop functionality together with SwiftData. That requires my model to conform Transferable. And Transferable requires to conform Codable. My code doesn't compile with this error: Type 'Item' does not conform to protocol 'Decodable/Encodable'. The error appears right after I add @Model macro. Is there a solution or a workaround? Here's my code: @Model final class Item: Transferable, Codable { let createdAt: Date static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .myCustomType) } init() { self.createdAt = .now } } extension UTType { static let myCustomType = UTType(exportedAs: "com.olexgreen.mytype") } Thank you very much
Posted
by olexgreen.
Last updated
.
Post not yet marked as solved
2 Replies
502 Views
Scenario: The following Swift code uses NSItemProviderWriting to load a file from some data source async (The code actually just uses a for loop to simulate the time it needs to load the file). It returns the file url then. This code is used for drag & drop behavior in a macOS app from an app to another app. As the other app does only support file URLs as drop types, I can't send over the data itself. class AnyFile: NSObject, NSItemProviderWriting { let url: URL init(url: URL) { self.url = url } static var writableTypeIdentifiersForItemProvider: [String] { return [UTType.fileURL.identifier] } func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { let count = 100000 let progress = Progress(totalUnitCount: Int64(count)) print("a") Task { print("b") for i in 0...100000 { progress.completedUnitCount = Int64(i) print(i) } print("c") completionHandler(url.dataRepresentation, nil) print("d") } print("e") return progress } } Problem: Drag & drop works, but when I start to drag the view (SwiftUI view using .onDrag), the view gets stuck as long as the loop is running. It is not clear to me why this happens as the loop us running inside a task. The console output also shows that progress is returned before the loop as finished. But still, it is stuck until the end of the loop. So the user experience is like not using async and the task. Log output (shortened) a e b 0 ... 100000 c d Actual Question: Why is this Swift code for dragging files not behaving asynchronously even though it uses Task, completionHandler, and async/await constructs? Alternatives tried: I'm not bound to NSItemProviderWriting in particular. I have tried other ways, like Transferable, .draggable(), and NSItemProvider.registerFileRepresentation. But either they won't return a URL, or do not allow async at all. I also tried AppKit instead of SwiftUI with similar issues.
Posted Last updated
.
Post not yet marked as solved
0 Replies
385 Views
Hi All, I have successfully implemented drag & drop of files from and to other apps on macOS successfully using different methods. Including NSFilePromiseProvider for example. There is one app however, that I use on a regular basis, that only support file urls as drop types. So I have to use public.file-url to drag & drop files there. The problem is that the file does not exist when dragging starts. That's why I would like to send a URL promise to the app, instead of a file promise. I can't create the file beforehand because then I would need to create hundreds of large files which will just take up space. So whenever I drag an item from my app to the other app, then the file shall be created and the url shall be sent to that app to be opened. But as the other app only checks the pasteboard for urls without handling promises, this is not working. I do have their code available, but can't change the code. Question: Is there a way in Swift on macOS to drag and drop a an item to another app so that upon mouse up on the other app some async tasks is executed and at the end the other app receives the URL as a result of the async task?
Posted Last updated
.
Post not yet marked as solved
7 Replies
1.9k Views
I've discovered an issue with using iOS 16's Transferable drag-and-drop APIs for SwiftUI. The dropDestination modifier does not work when applied to a subview of a List. This code below will not work, unless you replace the List with a VStack or any other container (which, of course, removes all list-specific rendering). The draggable modifier will still work and the item will drag, but the dropDestination view won't react to it and neither closure will be called. struct MyView: View { var body: some View { List { Section { Text("drag this title") .font(.largeTitle) .draggable("a title") } Section { Color.pink .frame(width: 400, height: 400) .dropDestination(for: String.self) { receivedTitles, location in true } isTargeted: { print($0) } } } } } Has anyone encountered this bug and perhaps found a workaround?
Posted Last updated
.
Post not yet marked as solved
1 Replies
435 Views
Problem When copyable is used with NavigationSplitView then it doesn't work The menu Edit > Copy is disabled Note When copyable is not used with a NavigationSplitView and used only with a plain List then it works. Question Is there anything I am missing? Feedback FB12990593 Platform macOS 14.0 Beta (23A5312d) Xcode 15.0 beta 6 (15A5219j) Steps to reproduce Run the app on mac Select some cars Press Command C Expected Behaviour Menu Edit > Copy should be enabled Pressing Command C should allow user to copy selected cars Actual Behaviour Menu Edit > Copy is disabled Pressing Command C doesn't allow user to copy selected cars Code struct ContentView: View { @State private var dataStore = DataStore() var body: some View { NavigationSplitView { Color.brown } detail: { CarListView(dataStore: dataStore) } } } struct CarListView: View { let dataStore: DataStore @State private var selectedCarIDs = Set<UUID>() var body: some View { List(selection: $selectedCarIDs) { ForEach(dataStore.cars) { car in CarCell(car: car) .draggable(car) } } .copyable(selectedCars()) } private func selectedCars() -> [Car] { dataStore.cars.filter { selectedCarIDs.contains($0.id) } } } struct CarCell: View { let car: Car var body: some View { VStack(alignment: .leading) { Text(car.name) Text("\(car.price)") } } } @Observable class DataStore { var cars = [ Car(name: "aaa", price: 10), Car(name: "bbb", price: 20), Car(name: "ccc", price: 30), Car(name: "ddd", price: 40) ] } struct Car: Codable, Transferable, Identifiable { let id: UUID let name: String let price: Int init(name: String, price: Int) { self.id = UUID() self.name = name self.price = price } static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .car) } } extension UTType { static let car = UTType("com.example.car")! }
Posted
by newwbee.
Last updated
.
Post not yet marked as solved
0 Replies
968 Views
I’m trying to use a ShareLink to share a PDF file. When using the file URL to the PDF directly, everything looks as I would expect: let fileURL = URL(filePath: "…") ShareLink(item: fileURL) But in my actual app, the PDF isn’t available right away and is expensive to create, so I would like to only create it on demand. The documentation on FileRepresentation sounds to me like this is a use case for a custom type that implements Transferable with a FileRepresentation as its transferRepresentation. Before adding all the actual code to generate the PDF, I’m now trying to write a simple type that wraps a file URL and leads to the same results as using the URL directly. And I’m failing miserably. This is what I tried: struct PDFFile: Transferable { var fileURL: URL static var transferRepresentation: some TransferRepresentation { FileRepresentation(exportedContentType: .pdf) { pdfFile in SentTransferredFile(pdfFile.fileURL) } } } …and then in the view: let fileURL = URL(filePath: "…") let pdfFile = PDFFile(fileURL: fileURL) ShareLink( item: pdfFile, preview: SharePreview(fileURL.deletingPathExtension().lastPathComponent, image: Image(systemName: "doc.richtext"), icon: Image(systemName: "doc")) ) Why are no sharing services showing up? Why is there no icon? I also tried using .fileURL as the exportedContentType, which then makes the sharing services show up, but actually sharing the file leads to an empty file being shared whose filename is garbage (it looks like the system tries to decode the PDF data as a UTF-8 string and use that as the filename). So my question is: Is it possible to replicate the behavior of sharing a file URL with a custom type that asynchronously generates the data to share?
Posted Last updated
.
Post marked as solved
3 Replies
543 Views
I've created a library that defines an encoded reference type, and was in the process of adding Transferrable conformance to the main class that represents the data. Doing so wants a type defined for the transferrable, so I'm adding a type for this data representation into the library. The extension on UniformTypeIdentifiers is trivial, but I'd like to also mark that the type itself conforms to public.data (UTType.data). Since this is in a swift package, there isn't an application-relevant Info.plist that would normally hold these additional details. Can I add the conformance through the library? Or is the whole aspect of Transferrable and associated UTTypes expected to be something only defined at the application level?
Posted
by heckj.
Last updated
.
Post not yet marked as solved
0 Replies
504 Views
Hello, I am building contact form that allows to attach screenshots and screen recordings. The PhotosPicker part is relatively straightforward but I am not sure how to properly import the selected items. The binding is of type [PhotosPickerItem] which requires (at least for my current implementation) to first know if the item is image or video. I have this not so pretty code to detect if the item is video: let isVideo = item.supportedContentTypes.first(where: { $0.conforms(to: .video) }) != nil || item.supportedContentTypes.contains(.mpeg4Movie) Which for screen recordings seems to work only because I ask about .mpeg4Movie and then I have this struct: struct ScreenRecording: Transferable { let url: URL static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .mpeg4Movie) { video in SentTransferredFile(video.url) } importing: { received in let copy = URL.temporaryDirectory.appending(path: "\(UUID().uuidString).mp4") try FileManager.default.copyItem(at: received.file, to: copy) return Self.init(url: copy) } } } Notice here I have just the .mpeg4Movie content type, I couldn't get it to work with more generic ones like movie and I am afraid this implementation could soon break if the screen recordings change video format/codec. And finally my logic to load the item: if isVideo { if let movie = try? await item.loadTransferable(type: ScreenRecording.self) { viewModel.addVideoAttachment(movie) } } else { if let data = try? await item.loadTransferable(type: Data.self) { if let uiImage = UIImage(data: data) { viewModel.addScreenshotAttachment(uiImage) } } } I would like to make this more "future proof" and less error prone - particularly the screen recordings part. I don't even need the UIImage since I am saving the attachments as files, I just need to know if the attachment is screenshot or video and get its URL. Thanks!
Posted
by nemecek_f.
Last updated
.
Post not yet marked as solved
1 Replies
1.1k Views
I'm having a hard time reconciling DocumentGroup with the new APIs using Transferable. Setting up an app with DocumentGroup using a FileDocument type gives you undo/redo and file-specific app opening behavior out of the box (even though the navigation view implicitly present in DocumentGroup is a nightmare to work with). Now with Transferable we're given the ability to set up representations to share, drag/drop, copy/paste, etc. The point where these collide in a confusing way is in the .navigationDocument API., which sets up elements in the navigation bar to interact with a "document" that is Transferable. This would be great to include in a DocumentGroup scene backed by a FileDocument, but FileDocument is not currently Transferable and furthermore the Navigation View underlying the DocumentGroup isn't easily exposed. This really muddies the story around how to build document-based applications. Where does DocumentGroup fit in now that Transferable exists? Should I be providing my own conformance to Transferable on my FileDocument, reach down into the implicit NavigationView of DocumentGroup to get the new .navigationDocument functionality? Is DocumentGroup soon to be deprecated (or at least not for a more sophisticated use case) and apps should be built with Transferrable types in a normal WindowGroup that implements all of the other goodies that exist in DocumentGroup? Any clarity around the intention with DocumentGroup and how such an app would fit into a world of Transferables would be greatly appreciated!
Posted Last updated
.
Post not yet marked as solved
0 Replies
645 Views
Problem: On macOS, unable to drag multiple car items from FolderDetail List Single items from a list are draggable but multiple items are not draggable. Feedback FB10128110 I am really saddened that this is not fixed for over a year. Please look into this. Platform macOS 14 (beta 3), macOS 13 Steps to reproduce Run the code provided below Tap the sidebar button to show the sidebar Select "Folder 0" from the sidebar Drag "car a" into "Folder 1" (Go to Folder 2 to notice this happened successfully, you will be able to see "car a" in Folder 1) Select "Folder 0" from the sidebar Select "car a" and "car b" and try to drag them to "Folder 2" Expected Behaviour "car a" and "car b" must be both draggable (multiple items should be draggable). The entire cell needs to be draggable not just the Text. Actual Behaviour Though “car a” and “car b” are selected, when dragged only one of the 2 items is dragged You also can drag them only when dragging the Text unlike in iOS where you can drag the cell. Note: Same code works on iOS Code: UTType extension UTType { static var car = UTType(exportedAs: "com.example.DragAndDropListDemo.car") } Car import Foundation import CoreTransferable struct Car: Identifiable { var id: Int var name: String } //extension Car: Codable {} extension Car: Codable, Transferable { static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .car) } } Folder struct Folder: Identifiable, Hashable { var id: Int var name: String } DataStore class DataStore: ObservableObject { var folders = (0..<100).map { Folder(id: $0, name: "folder \($0)")} var cars = [0: [Car(id: 0, name:"car a"), Car(id: 1, name:"car b")], 1: [Car(id: 2, name:"car c"), Car(id: 3, name:"car d")]] } Views ContentView struct ContentView: View { @StateObject private var dataStore = DataStore() @State private var selectedFolder: Folder? var body: some View { NavigationSplitView { FolderList(selectedFolder: $selectedFolder, dataStore: dataStore) } detail: { FolderDetail(folder: selectedFolder, dataStore: dataStore) } } } FolderList struct FolderList: View { @Binding var selectedFolder: Folder? @ObservedObject var dataStore: DataStore var body: some View { List(dataStore.folders, selection: $selectedFolder) { folder in NavigationLink(value: folder) { Text(folder.name) .dropDestination(for: Car.self) { cars, location in print("cars = \(cars) location = \(location)") if let existingCars = dataStore.cars[folder.id] { dataStore.cars[folder.id] = existingCars + cars } else { dataStore.cars[folder.id] = cars } return true } } } } } FolderDetail struct FolderDetail: View { let folder: Folder? @ObservedObject var dataStore: DataStore @State private var selectedCarIDs = Set<Int>() var body: some View { if let folder { List(dataStore.cars[folder.id] ?? [], selection: $selectedCarIDs) { car in Text(car.name) .draggable(car) } } else { Text("no folder selected") } } }
Posted
by newwbee.
Last updated
.
Post not yet marked as solved
2 Replies
1.3k Views
In my app I try to use SwiftUI's ShareLink to offer sharing of the app's documents. I followed this video for defining the exported type and the document type. Unfortunately if I use any ShareLink initializer for sharing Transferable items, the option "save to files" is not offered on the displayed share sheet. (Only "copy" is offered, which works if pasted into the destination directory using the Files app, but that is not an acceptable workaround). PS: com.example.transferabletestis defined as conforming to com.apple.package import SwiftUI import UniformTypeIdentifiers extension UTType{     static let transferableTest = UTType(exportedAs: "com.example.transferabletest") } struct Document:Transferable{     static let filePackageURL = URL.documentsDirectory.appending(components: "0815.transferabletest")    public static var transferRepresentation: some TransferRepresentation {         FileRepresentation(exportedContentType: .transferableTest) { document in             _ = try? FileManager.default.createDirectory(at: Self.filePackageURL, withIntermediateDirectories: false)             FileManager.default.createFile(atPath: Self.filePackageURL.appending(components: "data").path(), contents: "Transferable Test\n".data(using: .utf8))             return SentTransferredFile(Document.filePackageURL)         }     } } struct ContentView: View {     var body: some View {         ShareLink("Share as tranferable item", item: Document(), preview: SharePreview("Test"))     } } Is this a bug? What am I doing wrong? Sharing the document using the ShareLink for URLs does offer "save to files" but I can't use that in my app for various reasons.
Posted
by Dirk-FU.
Last updated
.
Post not yet marked as solved
4 Replies
2.8k Views
In my app, I'd like to be able to share a .csv file via ShareLink and Transferable. I watched the "Meet Transferable" WWDC22 video and it should be possible as the presenter demonstrated that use case. However, when I try this on my end, I am able to share the content but somehow it is treated by iOS as plaintext and when sharing by email or messages, it will just add the text content to the body. If I try to share via AirDrop, it creates a random filename with the .txt extension even though I specify .commaSeparatedText. The only way this somewhat works is when saving to files. It will save as a .csv file but the filename is set to "comma-separated values". Here's some code: struct MyArchive {     enum ValidationError: Error {         case invalid     }     var filename: String { return "myarchive.csv"     }          init(csvData: Data) throws {         //...     }     func convertToCSV() throws -> Data {         let test = "Name,Email\nPete,pete@example.com"         if let data = test.data(using: .utf8) {             return data         }         else {             throw ValidationError.invalid         }     }  } extension MyArchive: Transferable {     static var transferRepresentation: some TransferRepresentation {         DataRepresentation(contentType: .commaSeparatedText) { archive in             try archive.convertToCSV()         } importing: { data in             try MyArchive(csvData: data)         }     } } And in my View: struct View: View { var body: some View { //... let csv = MyArchive() ShareLink( item: csv, preview: SharePreview(                         csv.filename,                         image: Image(systemName: "doc.plaintext")                     ) ) } } I'm at the point that I wonder if I'm doing something wrong or this just doesn't work in iOS 16 beta 1. Any hints? Thanks!
Posted
by Lucky7.
Last updated
.