I feel like I’m missing something here but can’t figure it out.
I’ve got two SwiftData models joined as a relationship. The idea being that the user drags the name of a device from a list and they can drop it into the view.
Right now, I’ve got the list somewhat working and can drag items from it, I haven’t made the main view just yet so the drop destination is the ‘Hello World’ text.
I’ve made the data models conform to Codable and Transferable, but I believe it’s the encode function that’s causing a runtime crash and throwing EXC_BAD_ACCESS. I’ve got a print statement in the encode function to print the data once it’s ‘dropped’ but it seems that any data sent to the encode function is empty/nil.
This is the file containing the storage models:
@Model class Manufacturers: Codable {
@Attribute(.unique) var id: UUID
var manufacturer: String
@Attribute(.externalStorage) var logo: Data // Image converted to Base64 and stored as Data
@Relationship(deleteRule: .cascade, inverse: Devices.manufacturer) var devices = [Devices]()
init(id: UUID, manufacturer: String, logo: Data, devices: [Devices]? = nil) {
self.id = id
self.manufacturer = manufacturer
self.logo = logo
if let devicesUnwrapped = devices {
if devicesUnwrapped.isEmpty == false {
self.devices = devicesUnwrapped
}
}
}
enum CodingKeys: CodingKey {
case id
case manufacturer
case logo
case devices
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
manufacturer = try container.decode(String.self, forKey: .manufacturer)
if let logoData = try? container.decode(Data.self, forKey: .logo) {
logo = logoData
} else {
logo = Data()
}
devices = try container.decode([Devices].self, forKey: .devices)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(manufacturer, forKey: .manufacturer)
try container.encode(logo, forKey: .logo)
try container.encode(devices, forKey: .devices)
}
}
@Model
class Devices: Identifiable, Codable, Transferable {
@Attribute(.unique) var id: UUID
var manufacturer: Manufacturers?
var name: String
init(id: UUID, manufacturer: Manufacturers? = nil, name: String) {
self.id = id
if manufacturer?.isDeleted == false {
self.manufacturer = manufacturer
}
self.name = name
}
enum CodingKeys: CodingKey {
case id
case manufacturer
case name
}
// Following is needed to conform to Codable
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
manufacturer = try container.decode(Manufacturers.self, forKey: .manufacturer)
name = try container.decode(String.self, forKey: .name)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(manufacturer, forKey: .manufacturer)
try container.encode(name, forKey: .name)
print(container.codingPath)
}
static var transferRepresentation: some TransferRepresentation {
CodableRepresentation(for: Devices.self, contentType: .devices)
}
}
extension UTType {
static var devices: UTType {
UTType(importedAs: "com.me.app")
}
}
This is the view file:
struct MainView: View {
@Environment(.modelContext) var modelContext
@State private var listIsOpen: Bool = true
var body: some View {
GeometryReader { geo in
ZStack {
Text("Hello World")
.dropDestination(for: Devices.self) { receivedPayload, _ in
if !receivedPayload.isEmpty {
print(receivedPayload[0])
return true
}
return false
} isTargeted: {
print($0)
}
VStack {
Spacer()
HStack {
Spacer()
Image(systemName: "sidebar.squares.right")
.font(Font.custom("SF Pro Rounded", size: listIsOpen ? 20 : 16))
.foregroundStyle(listIsOpen ? Color.blue : Color.gray)
.onTapGesture {
listIsOpen.toggle()
}
.animation(.easeOut(duration: 0.2), value: listIsOpen)
.padding(.trailing)
}
}.padding(.bottom)
if(listIsOpen){
list
.frame(width: 240, height: geo.size.height - 120)
.background(Color.listBackgroundColor)
.clipShape(.rect(cornerRadius: 11))
.padding(.trailing, 40)
.padding(.bottom, 20)
}
}
}
}
// MARK: List View
@Query var manufacturers: [Manufacturers]
var list: some View {
VStack {
List(manufacturers) { manufacturer in
Section {
ForEach (manufacturer.devices, id: .id) { device in
Text(device.name)
.draggable(device) {
Text(device.name)
.frame(width: 70, height: 70)
}
.font(.custom("SF Pro", size: 14))
.padding(.vertical, 2)
}
} header: {
Text(manufacturer.manufacturer)
.font(.custom("SF Pro Rounded", size: 18))
}.headerProminence(.standard)
}
}
}
}
Any advice on what to check? Also as I’m still learning and this is the first thing I’ve made, any tips to improve would be helpful.
I’ve only tried playing around with the encode func/decode init but I’m really not sure why it’s crashing
sam0701 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.