带有 Codable 的 SwiftData

问题描述 投票:0回答:1

我正在尝试将 SwiftData 集成到我的网络模型中以合并本地持久性。为了实现这一目标,我需要确保我的 Codable 模型符合 SwiftData。但是,我在构建过程中遇到了错误。有其他人遇到类似问题并找到解决方案吗?

以下是我的模型:我省略了某些模型属性以启用帖子的发布。


import SwiftData
import SwiftUI

// MARK: - Game
@Model
class Game: Codable, Identifiable, Hashable {
    
    let id: Int?
    let name: String?
    let cover: Cover?
    let firstReleaseDate: Int?
    let summary: String?
    let totalRating: Double?
    let ratingCount: Int?
    let genres: [Genre]?
    let platforms: [Platform]?
    let releaseDates: [ReleaseDate]?
    let screenshots: [Cover]?
    let gameModes: [GameMode]?
    let videos: [Video]?
    let websites: [Website]?
    let similarGames: [Int]?
    let artworks: [Artwork]?
    
    enum CodingKeys: String, CodingKey {
        case id, name, cover, artworks, genres, platforms, screenshots, summary, videos, websites
        case firstReleaseDate = "first_release_date"
        case releaseDates = "release_dates"
        case totalRating = "total_rating"
        case ratingCount = "rating_count"
        case gameModes = "game_modes"
        case similarGames = "similar_games"
    }
    
    init(
        id: Int? = nil,
        name: String? = nil,
        cover: Cover? = nil,
        firstReleaseDate: Int? = nil,
        summary: String? = nil,
        totalRating: Double? = nil,
        versionTitle: String? = nil,
        ratingCount: Int? = nil,
        genres: [Genre]? = nil,
        platforms: [Platform]? = nil,
        releaseDates: [ReleaseDate]? = nil,
        screenshots: [Cover]? = nil,
        gameModes: [GameMode]? = nil,
        videos: [Video]? = nil,
        websites: [Website]? = nil,
        similarGames: [Int]? = nil,
        artworks: [Artwork]? = nil
    ) {
        self.id = id
        self.name = name
        self.cover = cover
        self.firstReleaseDate = firstReleaseDate
        self.summary = summary
        self.totalRating = totalRating
        self.ratingCount = ratingCount
        self.genres = genres
        self.platforms = platforms
        self.releaseDates = releaseDates
        self.screenshots = screenshots
        self.gameModes = gameModes
        self.videos = videos
        self.websites = websites
        self.similarGames = similarGames
        self.artworks = artworks
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int?.self, forKey: .id)
        self.name = try container.decode(String?.self, forKey: .name)
        self.firstReleaseDate = try container.decode(Int?.self, forKey: .firstReleaseDate)
        self.summary = try container.decode(String?.self, forKey: .summary)
        self.totalRating = try container.decode(Double?.self, forKey: .totalRating)
        self.genres = try container.decode([Genre]?.self, forKey: .genres)
        self.platforms = try container.decode([Platform]?.self, forKey: .platforms)
        self.releaseDates = try container.decode([ReleaseDate]?.self, forKey: .releaseDates)
        self.screenshots = try container.decode([Cover]?.self, forKey: .screenshots)
        self.gameModes = try container.decode([GameMode]?.self, forKey: .gameModes)
        self.videos = try container.decode([Video]?.self, forKey: .videos)
        self.websites = try container.decode([Website]?.self, forKey: .websites)
        self.similarGames = try container.decode([Int]?.self, forKey: .similarGames)
        self.artworks = try container.decode([Artwork]?.self, forKey: .artworks)
        self.cover = try container.decode(Cover?.self, forKey: .cover)
        self.ratingCount = try container.decode(Int?.self, forKey: .ratingCount)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(cover, forKey: .cover)
        try container.encode(artworks, forKey: .artworks)
        try container.encode(firstReleaseDate, forKey: .firstReleaseDate)
        try container.encode(genres, forKey: .genres)
        try container.encode(name, forKey: .name)
        try container.encode(platforms, forKey: .platforms)
        try container.encode(releaseDates, forKey: .releaseDates)
        try container.encode(screenshots, forKey: .screenshots)
        try container.encode(summary, forKey: .summary)
        try container.encode(totalRating, forKey: .totalRating)
        try container.encode(ratingCount, forKey: .ratingCount)
        try container.encode(gameModes, forKey: .gameModes)
        try container.encode(videos, forKey: .videos)
        try container.encode(websites, forKey: .websites)
        try container.encode(similarGames, forKey: .similarGames)
    }
}

// MARK: - Artwork
@Model
class Artwork: Codable, Hashable {
    let id: Int?
    let url: String?
    
    enum CodingKeys: CodingKey {
        case id
        case url
    }
    
    init(id: Int?, url: String?) {
        self.id = id
        self.url = url
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int?.self, forKey: .id)
        self.url = try container.decode(String?.self, forKey: .url)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(url, forKey: .url)
    }
}

// MARK: - Cover
@Model
class Cover: Codable, Hashable {
    let id: Int?
    let url: String?
    
    enum CodingKeys: CodingKey {
        case id
        case url
    }
    
    init(id: Int?, url: String?) {
        self.id = id
        self.url = url
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int?.self, forKey: .id)
        self.url = try container.decode(String?.self, forKey: .url)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(url, forKey: .url)
    }
}

// MARK: - Genre
@Model
class Genre: Codable, Hashable {
    let id: Int?
    let name: String?
    
    enum CodingKeys: CodingKey {
        case id
        case name
    }
    
    init(id: Int?, name: String?) {
        self.id = id
        self.name = name
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int?.self, forKey: .id)
        self.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(name, forKey: .name)
    }
}

// MARK: - GameMode
@Model
class GameMode: Codable, Hashable {
    ////
}

// MARK: - Platform
@Model
class Platform: Codable, Hashable {
    ////
}

// MARK: - ReleaseDate
@Model
class ReleaseDate: Codable, Hashable, Comparable {
   ////
}

// MARK: - Video
@Model
class Video: Codable, Hashable {
    ////
}

// MARK: - Website
@Model
class Website: Codable, Hashable {
    //// 
}

尝试转换 Codable 模型以符合 Swift Data @Model Macro

swift codable swift-data
1个回答
0
投票

SwiftData(或任何新宏)似乎与

Codable
不兼容。

它们本身符合

Codable
,并且生成的 JSON 看起来不像基于开发人员创建的属性的标准 JSON。

没有任何文档支持或反对这一点,但苹果使用 SwiftData 复制服务器数据的一个例子是,他们创建了一个辅助

struct
并使用
convenience init
进行初始化。

convenience init(from feature: GeoFeatureCollection.Feature) {
    self.init(
        code: feature.properties.code,
        magnitude: feature.properties.mag,
        time: feature.properties.time,
        name: feature.properties.place,
        longitude: feature.geometry.coordinates[0],
        latitude: feature.geometry.coordinates[1]
    )
}

https://developer.apple.com/documentation/swiftdata/maintaining-a-local-copy-of-server-data

© www.soinside.com 2019 - 2024. All rights reserved.