-
Meet Transferable
Meet Transferable: a model-layer protocol that allows for effortless support for sharing, drag and drop, copy/paste, and other features in your app.
We'll explore how you can use the API for common use cases, and take advantage of advanced features to customize the behavior. We'll also share how you can optimize for memory efficiency when dealing with large amounts of data. Whether you're extending your models to share with other applications as strings or images or creating custom declared data types, Transferable can help you facilitate a great experience in your app.Recursos
Videos relacionados
WWDC22
- Build a productivity app for Apple Watch
- Enhance collaboration experiences with Messages
- Integrate your custom collaboration app with Messages
- What's new in SwiftUI
Tech Talks
-
Buscar este video…
-
-
4:36 - Declaring a custom content type
import UniformTypeIdentifiers // also declare the content type in the Info.plist extension UTType { static var profile: UTType = UTType(exportedAs: "com.example.profile") } -
5:10 - PasteButton interface
import SwiftUI struct Profile { private var funFacts: [String] = [] mutating func addFunFacts(_ newFunFacts: [String]) { funFacts.append(newFunFacts) } } struct PasteButtonView: View { @State var profile = Profile() var body: some View { PasteButton(payloadType: String.self) { funFacts in profile.addFunFacts(funFacts) } } } -
5:19 - Drag and Drop
import SwiftUI struct PortraitView: View { @State var portrait: Image var body: some View { portrait .cornerRadius(8) .draggable(portrait) .dropDestination(payloadType: Image.self) { (images: [Image], _) in if let image = images.first { portrait = image return true } return false } } } -
5:27 - Sharing
import SwiftUI struct Profile { var name: String } struct ProfileView: View { @State private var portrait: Image var model: Profile var body: some View { VStack { portrait Text(model.name) } .toolbar { ShareLink(item: portrait, preview: SharePreview(model.name)) } } } -
6:34 - Profile structure
import Foundation struct Profile: Codable { var id: UUID var name: String var bio: String var funFacts: [String] var video: URL? var portrait: URL? } -
7:31 - CodableRepresentation
import CoreTransferable import UniformTypeIdentifiers struct Profile: Codable { var id: UUID var name: String var bio: String var funFacts: [String] var video: URL? var portrait: URL? } extension Profile: Codable, Transferable { static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .profile) } } // also declare the content type in the Info.plist extension UTType { static var profile: UTType = UTType(exportedAs: "com.example.profile") } -
8:30 - DataRepresentation
import CoreTransferable import UniformTypeIdentifiers struct ProfilesArchive { init(csvData: Data) throws { } func convertToCSV() throws -> Data { Data() } } extension ProfilesArchive: Transferable { static var transferRepresentation: some TransferRepresentation { DataRepresentation(contentType: .commaSeparatedText) { archive in try archive.convertToCSV() } importing: { data in try ProfilesArchive(csvData: data) } } } -
9:14 - FileRepresentation
import CoreTransferable struct Video: Transferable { let file: URL 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) } } static func copyVideoFile(source: URL) throws -> URL { let moviesDirectory = try FileManager.default.url( for: .moviesDirectory, in: .userDomainMask, appropriateFor: nil, create: true ) var destination = moviesDirectory.appendingPathComponent( source.lastPathComponent, isDirectory: false) if FileManager.default.fileExists(atPath: destination.path) { let pathExtension = destination.pathExtension var fileName = destination.deletingPathExtension().lastPathComponent fileName += "_\(UUID().uuidString)" destination = destination .deletingLastPathComponent() .appendingPathComponent(fileName) .appendingPathExtension(pathExtension) } try FileManager.default.copyItem(at: source, to: destination) return destination } } -
10:05 - ProxyRepresentation
import CoreTransferable import UniformTypeIdentifiers struct Profile: Codable { var id: UUID var name: String var bio: String var funFacts: [String] var video: URL? var portrait: URL? } extension Profile: Transferable { static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .profile) ProxyRepresentation(exporting: \.name) } } // also declare the content type in the Info.plist extension UTType { static var profile: UTType = UTType(exportedAs: "com.example.profile") } -
11:34 - Proxy and file representations
import CoreTransferable struct Video: Transferable { let file: URL static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .mpeg4Movie) { SentTransferredFile($0.file) } importing: { received in let copy = try Self.copyVideoFile(source: received.file) return Self.init(file: copy) } ProxyRepresentation(exporting: \.file) } static func copyVideoFile(source: URL) throws -> URL { let moviesDirectory = try FileManager.default.url( for: .moviesDirectory, in: .userDomainMask, appropriateFor: nil, create: true ) var destination = moviesDirectory.appendingPathComponent( source.lastPathComponent, isDirectory: false) if FileManager.default.fileExists(atPath: destination.path) { let pathExtension = destination.pathExtension var fileName = destination.deletingPathExtension().lastPathComponent fileName += "_\(UUID().uuidString)" destination = destination .deletingLastPathComponent() .appendingPathComponent(fileName) .appendingPathExtension(pathExtension) } try FileManager.default.copyItem(at: source, to: destination) return destination } } -
12:57 - Exporting condition
import CoreTransferable import UniformTypeIdentifiers struct ProfilesArchive { var supportsCSV: Bool { true } init(csvData: Data) throws { } func convertToCSV() throws -> Data { Data() } } extension ProfilesArchive: Transferable { static var transferRepresentation: some TransferRepresentation { DataRepresentation(contentType: .commaSeparatedText) { archive in try archive.convertToCSV() } importing: { data in try Self(csvData: data) } .exportingCondition { $0.supportsCSV } } }
-