Transferable ProxyRepresentation closure result error when output is an array in SwiftUI?

166 views Asked by At

I am trying to create an array of Transferable URLs (ie [URL]) for a ShareLink (ie various formats the user can choose at the same time), but cannot get it to work in SwiftUI. The reason I need this is that currently when I open the View with a simple ShareLink with the url (for a pdf and an xls file) it will create multiple copies of these files, presumably each time the view refreshes. I only want it to create the files when the user taps the ShareLink button so their urls can then be "shared". Hence, I think I need a ProxyRepresentation Transferable. I've found a posting that is equivalent for an Image. If I then change this to output an [Image] it fails with the same error that I am getting. My code for a single URL also compiles and works but the [URL] does not.

Here is the equivalent example with the source code that works:

/// From: https://www.dimillian.app/snippets
/// Compiles and works - outputs an Image view
struct AsyncImageTransferable: Codable, Transferable {
  let url: URL
 
  func fetchAsImage() async -> Image {
    let data = try? await URLSession.shared.data(from: url).0
    guard let data, let uiimage = UIImage(data: data) else {
      return Image(systemName: "photo")
    }
    return Image(nsImage: uiimage)
  }
 
  static var transferRepresentation: some TransferRepresentation {
    ProxyRepresentation { media in
      await media.fetchAsImage()
    }
  }
}

and the code that brings up the error when trying to output an [Image]: Error: Cannot convert value of type '[Image]' to closure result type 'AsyncImageArrayTransferable'

/// Adapted from: https://www.dimillian.app/snippets
/// Aims to output an array of Image (ie [Image]) but does not complile
/// Error: Cannot convert value of type '[Image]' to closure result type 'AsyncImageArrayTransferable'
/// on await media.fetchAsImage()
/// How to fix to put out an array of something (eg [Image])?
struct AsyncImageArrayTransferable: Codable, Transferable {
  let url: URL
 
  func fetchAsImage() async -> [Image] {
    let data = try? await URLSession.shared.data(from: url).0
    guard let data, let uiimage = UIImage(data: data) else {
      return [Image(systemName: "photo")]
    }
    return [Image(nsImage: uiimage)]
  }
 
  static var transferRepresentation: some TransferRepresentation {
      ProxyRepresentation { (media: AsyncImageArrayTransferable) in
      await media.fetchAsImage()
    }
  }
}
 

Can anyone tell me what I'm doing wrong? This should work in both iOS and macOS environments. Any help appreciated.

I have tried multiple variations and reviewed multiple Stack Overflow questions and answers. I could not find any relevant Transferable questions that try to use this for the ShareLink(items:...) initialiser.

1

There are 1 answers

0
Sweeper On BEST ANSWER

Image is Transferable, but [Image] is not.

Rather than making one Transferable item that represents an array of things. Make an array of the AsyncImageTransferable you wrote already.

ShareLink(items: [
    AsyncImageTransferable(url: url1),
    AsyncImageTransferable(url: url2),
    AsyncImageTransferable(url: url3),
    // etc
]) { image in 
    SharePreview(...) // make a preview for each one of the images...
}