New ShareLink with custom type is not working

Hi everyone! 

I want to share audio files with the new ShareLink in SwiftUI. I've a Recording entity from Core Data, witch store the URL from the audio file and the file itself is store in the FileManger. I already make Recording to conform Transferable protocol. But in the line of the Sharelink appears an error compiler: "No exact matches in call to initializer".

Here is the code:

Recording entity:


    @nonobjc public class func fetchRequest() -> NSFetchRequest<Recording> {
        return NSFetchRequest<Recording>(entityName: "Recording")
    }

    @NSManaged public var date: Date
    @NSManaged public var id: UUID
    @NSManaged public var url: String
    @NSManaged public var title: String

}

extension Recording : Identifiable, Transferable {
    // Transferable protocol
    static var containerUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

    public static var transferRepresentation: some TransferRepresentation {
        FileRepresentation(exportedContentType: .audio) { audio in
            SentTransferredFile(URL(string: audio.url)!)
        }
    }
}

View:


@ObservedObject var recording: Recording

  var body: some View {
        NavigationStack {
            VStack(spacing: 20){

                VStack {
                    Text(recording.title)
                        .font(.title)
                        .bold()
                    Text("\(recording.date, format: .dateTime)")
                        .foregroundColor(.secondary)
                }
             }
        }
     .toolbar {
           ToolbarItem(placement: .navigationBarLeading) {
               ShareLink(item: recording) { // This line gives the error: No exact matches in call to initializer 
                   Image(systemName: "square.and.arrow.up")
               }
           }
   }

Any idea? I have tried to simplify the code so let me know if I have forgotten something. Thanks!

You are using the ShareLink initialiser that accepts a String or URL as the item parameter.

You instead need to use an initialiser with the preview parameter which accepts a Transferable object and requires a SharePreview.

Thanks for the response!

I updated the code to the initializer with the preview parameter and now the code compile but I have a problem with this unwrap URL: SentTransferredFile(URL(string: audio.url)!) And since the url is a String, I have to use URL(string), is there any way to deal with this optional?

I was watching this session from the WWDC22, minute 9:14, and here they use another approach:

static var transferRepresentation: some TransferRepresentation {
       FileRepresentation(contentType: .mpeg4Movie) { 
           SentTransferredFile($0.file)
       } importing: { received in
           let destination = try Self.copyVideoFile(source: received.file)
           return Self.init(file: destination)
       }
   }

This makes sense but when I apply it in my own code I have problems with the line return Self.init(file: destination), since in my case I have an entity called Recording, without any variable called "File", but if I understand correctly, I must associate destination to Recording.url, is this correct?

is there any way to deal with this optional?

What error are you getting exactly? Is it a simple "Unexpectedly found nil while unwrapping an Optional value" sort of thing?

You will need to check that the value in the url property is a genuine URL. You could provide a default URL, maybe this:

URL(fileURLWithPath: "/dev/null")

but it's up to you and how you manage that url property.

I must associate destination to Recording.url

In the importing closure you would need to return an instance of Recording, given the file URL (received.file).

What the example it doing is copying the received file to a location in the user's file system and using that new URL to create a Video object. If you look at the Copy Code snippets for that session, you can see the contents of the Video.copyVideoFile method.

So yes, the received/copied destination file URL needs to be assigned to the Recording.url property.



‎If there are additional issues, please create a new post as this one is about a different (solved?) problem. Don't forget to close this thread.

You will need to check that the value in the url property is a genuine URL

I used nil coalescing to provide a default URL URL(fileURLWithPath: "/dev/null"), but every time I tried to use the Sharesheet, nothing happens and the debug area shows this error: [ShareSheet] cancelled request - error: The operation couldn’t be completed. Invalid argument. Sharing finished with error: Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument" at SwiftUI/SharingActivityPickerBridge.swift:266

So I think the main issue is that, for whatever reason the URL is nil and I can't understand why because in the Recoding model the url is not even optional. The only thing I can think right now is that the URL is a String instead of URL (that's why I need to use URL(string:) in the SentTransferredFile part, to convert the string into an URL) and maybe this is the problem with the optional. Any idea? Many thanks!

New ShareLink with custom type is not working
 
 
Q