SwiftData迁移报错:CLLocationCoordinate2D需遵循PersistentModel协议
解决SwiftData中CLLocationCoordinate2D数组的持久化问题
错误原因很明确:SwiftData的@Model类仅支持持久化基础类型、PersistentModel对象,或符合Codable的结构体/枚举。CLLocationCoordinate2D不属于以上范畴,所以直接将[CLLocationCoordinate2D]作为属性会触发报错。
下面给你两种适合新手的解决方案:
方案一:自定义可持久化的坐标结构体
把CLLocationCoordinate2D转换成自定义的Codable结构体,SwiftData原生支持存储这类值类型数组。
- 定义坐标转换结构体
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) } }
- 修改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
相关产品推荐
相关产品推荐

