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

SwiftData迁移报错:CLLocationCoordinate2D需遵循PersistentModel协议

解决SwiftData中CLLocationCoordinate2D数组的持久化问题

错误原因很明确:SwiftData的@Model类仅支持持久化基础类型、PersistentModel对象,或符合Codable的结构体/枚举。CLLocationCoordinate2D不属于以上范畴,所以直接将[CLLocationCoordinate2D]作为属性会触发报错。

下面给你两种适合新手的解决方案:

方案一:自定义可持久化的坐标结构体

把CLLocationCoordinate2D转换成自定义的Codable结构体,SwiftData原生支持存储这类值类型数组。

  1. 定义坐标转换结构体
import CoreLocation

// 符合Codable、Hashable的自定义坐标结构体
struct Coordinate: Codable, Hashable {
    let latitude: Double
    let longitude: Double
    
    // 从CLLocationCoordinate2D转换
    init(_ coordinate: CLLocationCoordinate2D) {
        self.latitude = coordinate.latitude
        self.longitude = coordinate.longitude
    }
    
    // 转回CLLocationCoordinate2D
    var clCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }
}
  1. 修改Stage类的属性
@Model
class Stage: Identifiable, Hashable {
    let id: String = UUID().uuidString
    var name: String
    var route: [Coordinate] // 替换为自定义结构体数组
    var length: Double
    var text: String
    var completed: Bool

    init(id: String,
         name: String,
         route: [CLLocationCoordinate2D],
         length: Double,
         text: String,
         completed: Bool) {
        self.id = id
        self.name = name
        self.route = route.map(Coordinate.init) // 初始化时转换类型
        self.length = length
        self.text = text
        self.completed = completed
    }
    
    // 方便直接获取CLLocationCoordinate2D数组的计算属性
    var clRoute: [CLLocationCoordinate2D] {
        route.map(\.clCoordinate)
    }
    
    // 手动实现Hashable(基于唯一id)
    static func == (lhs: Stage, rhs: Stage) -> Bool {
        lhs.id == rhs.id
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

方案二:将坐标数组编码为Data存储

把[CLLocationCoordinate2D]通过JSON编码成Data(SwiftData支持存储Data类型),再通过计算属性对外提供原类型的访问接口。

import CoreLocation

@Model
class Stage: Identifiable, Hashable, Codable {
    let id: String = UUID().uuidString
    var name: String
    @Attribute(.externalStorage) private var routeData: Data // 存储编码后的二进制数据
    var length: Double
    var text: String
    var completed: Bool
    
    // 对外暴露的CLLocationCoordinate2D数组接口
    var route: [CLLocationCoordinate2D] {
        get {
            do {
                return try JSONDecoder().decode([CLLocationCoordinate2D].self, from: routeData)
            } catch {
                print("路线解码失败:\(error)")
                return []
            }
        }
        set {
            do {
                routeData = try JSONEncoder().encode(newValue)
            } catch {
                print("路线编码失败:\(error)")
            }
        }
    }

    init(id: String,
         name: String,
         route: [CLLocationCoordinate2D],
         length: Double,
         text: String,
         completed: Bool) {
        self.id = id
        self.name = name
        self.length = length
        self.text = text
        self.completed = completed
        // 初始化时完成编码
        do {
            self.routeData = try JSONEncoder().encode(route)
        } catch {
            print("初始化路线编码失败:\(error)")
            self.routeData = Data()
        }
    }
    
    // Codable协议要求的解码初始化方法
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        routeData = try container.decode(Data.self, forKey: .routeData)
        length = try container.decode(Double.self, forKey: .length)
        text = try container.decode(String.self, forKey: .text)
        completed = try container.decode(Bool.self, forKey: .completed)
    }
    
    // Codable协议要求的编码键
    enum CodingKeys: String, CodingKey {
        case id, name, routeData, length, text, completed
    }
    
    // 手动实现Hashable
    static func == (lhs: Stage, rhs: Stage) -> Bool {
        lhs.id == rhs.id
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

推荐方案一,因为它逻辑更直观,不需要处理复杂的编码解码异常,也更符合SwiftData的设计习惯。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 19:30:53