You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法自动合成:SwiftData中@Model的Landmark类为何不兼容Codable?

解决SwiftData @Model类无法自动合成Codable的问题

问题描述

将苹果官方Landmarks应用迁移至SwiftData时,标注@Model的Landmark类始终无法符合Encodable/Decodable协议,编译报错:

Type 'Landmark' does not conform to protocol 'Decodable'
Type 'Landmark' does not conform to protocol 'Encodable'

展开@Model宏时提示:

Cannot automatically synthesize 'Decodable' because 'any SwiftData.BackingData' does not conform to 'Decodable'

对应代码:

import Foundation
import SwiftUI
import CoreLocation
import SwiftData

@Model
final class Landmark: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var dezcription: String
    var isFavorite: Bool
    var isFeatured: Bool
    
    var category: Category
    private var coordinates: Coordinates
    private var imageName: String
    
    init(id:Int = Int.random(in: 2000...Int.max), name:String = "", park: String = "", state:String = "", dezcription: String = "", isFavorite: Bool = false, isFeatured:Bool = false, category: Category = Category.mountains, coordinates: Coordinates = Coordinates(latitude: 0, longitude: 0), imageName:String = "umbagog") {
        self.id = id
        self.name = name
        self.park = park
        self.state = state
        self.dezcription = dezcription
        self.isFavorite = isFavorite
        self.isFeatured = isFeatured
        self.category = category
        self.coordinates = coordinates
        self.imageName = imageName
        
    }

    enum Category: String, CaseIterable, Codable {
        case lakes = "Lakes"
        case rivers = "Rivers"
        case mountains = "Mountains"
    }

    var image: Image {
        Image(imageName)
    }
    
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

注:随机ID、默认坐标等设计问题并非本次核心。

已尝试但未解决的方法:

  • 注释/隔离疑似有问题的类型
  • 确保所有类型符合Codable协议
  • 初始化器包含所有属性
  • 查阅@Model类使用规范
  • 为Image计算属性添加@Transient标记
  • 将Coordinates和Category移至类外部
  • 添加唯一UUID属性

解决方法

问题根源在于@Model宏会自动为类注入any SwiftData.BackingData类型的关联属性,该类型不遵循Codable,导致系统无法自动合成Codable实现。必须手动实现Encodable和Decodable方法,仅处理自定义的属性:

  1. 定义CodingKeys枚举,指定需要编码/解码的属性
  2. 手动实现encode(to:)方法,编码所有自定义存储属性
  3. 手动实现required init(from:)方法,解码属性并创建实例

修改后的完整代码:

import Foundation
import SwiftUI
import CoreLocation
import SwiftData

@Model
final class Landmark: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var dezcription: String
    var isFavorite: Bool
    var isFeatured: Bool
    
    var category: Category
    private var coordinates: Coordinates
    private var imageName: String
    
    init(id:Int = Int.random(in: 2000...Int.max), name:String = "", park: String = "", state:String = "", dezcription: String = "", isFavorite: Bool = false, isFeatured:Bool = false, category: Category = Category.mountains, coordinates: Coordinates = Coordinates(latitude: 0, longitude: 0), imageName:String = "umbagog") {
        self.id = id
        self.name = name
        self.park = park
        self.state = state
        self.dezcription = dezcription
        self.isFavorite = isFavorite
        self.isFeatured = isFeatured
        self.category = category
        self.coordinates = coordinates
        self.imageName = imageName
    }

    // 手动实现Codable相关逻辑
    enum CodingKeys: String, CodingKey {
        case id, name, park, state, dezcription, isFavorite, isFeatured, category, coordinates, imageName
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(park, forKey: .park)
        try container.encode(state, forKey: .state)
        try container.encode(dezcription, forKey: .dezcription)
        try container.encode(isFavorite, forKey: .isFavorite)
        try container.encode(isFeatured, forKey: .isFeatured)
        try container.encode(category, forKey: .category)
        try container.encode(coordinates, forKey: .coordinates)
        try container.encode(imageName, forKey: .imageName)
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        park = try container.decode(String.self, forKey: .park)
        state = try container.decode(String.self, forKey: .state)
        dezcription = try container.decode(String.self, forKey: .dezcription)
        isFavorite = try container.decode(Bool.self, forKey: .isFavorite)
        isFeatured = try container.decode(Bool.self, forKey: .isFeatured)
        category = try container.decode(Category.self, forKey: .category)
        coordinates = try container.decode(Coordinates.self, forKey: .coordinates)
        imageName = try container.decode(String.self, forKey: .imageName)
    }

    enum Category: String, CaseIterable, Codable {
        case lakes = "Lakes"
        case rivers = "Rivers"
        case mountains = "Mountains"
    }

    var image: Image {
        Image(imageName)
    }
    
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

通过手动实现Codable逻辑,避开SwiftData注入的非Codable属性,即可让Landmark类同时满足SwiftData模型和Codable协议的要求。

内容的提问来源于stack exchange,提问作者Nerdy Bunz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:24:51