Swift 5游戏对话JSON文件创建与解析技术咨询
游戏对话JSON结构修正与Swift解析方案
一、当前JSON结构的问题及调整方案
你的JSON存在几个影响解析的问题,调整后才能和Swift代码正确匹配:
- 拼写错误:所有
diagloue键名需修正为dialogue(少写了字母a) - Speaker枚举值不匹配:
- 你的
Speaker枚举rawValue是驼峰格式(如CharacterA),但JSON里写的是"Character A"(带空格)、"protagonist"(全小写),需统一格式。建议JSON使用和枚举一致的驼峰/大小写:"CharacterA"代替"Character A""Protagonist"代替"protagonist"
- 你的
- 冗余字段:外层
chapter数组中每个对象的speaker字段冗余,对话列表已包含每个发言的角色,可直接删除简化结构。
调整后的JSON示例:
{ "chapter": [ { "conversation": [ { "speaker": "CharacterA", "dialogue": "Hello stranger, what brought you here?" }, { "speaker": "Protagonist", "dialogue": "I'm here to look for some guy." }, { "speaker": "CharacterA", "dialogue": "I've lived here all my life. Maybe I can help you." } ] }, { "conversation": [ { "speaker": "Protagonist", "dialogue": "Why is the gate closed?" }, { "speaker": "CharacterB", "dialogue": "No one is allowed to leave town until further notice." } ] } ] }
若需保留章节对应主要角色,可将外层speaker改为mainSpeaker,避免和对话内speaker混淆,同时调整Swift结构体对应。
二、Swift 5解析代码修正
你的解析代码需和自定义Speaker枚举、Dialogue结构体对齐,同时处理安全解包和枚举解码:
1. 统一数据模型
保留原有Speaker枚举,调整解析用结构体以匹配自定义Dialogue:
enum Speaker: String, Decodable { case Protagonist case CharacterA case CharacterB case CharacterC } // 原自定义Dialogue结构体,适配解析需求 struct Dialogue { var speaker: Speaker var messages: [String] // 从JSON单条对话初始化 init(speaker: Speaker, message: String) { self.speaker = speaker self.messages = [message] } } // 对应JSON的对话组结构 struct ConversationGroup: Decodable { let conversation: [SingleDialogue] // 解析JSON单条对话的临时结构体 struct SingleDialogue: Decodable { let speaker: Speaker let dialogue: String } // 转换为自定义Dialogue数组(支持按角色合并消息) func toDialogues() -> [Dialogue] { // 按角色分组消息 let grouped = Dictionary(grouping: conversation) { $0.speaker } return grouped.map { Dialogue(speaker: $0.key, message: $0.value.map { $0.dialogue }.joined(separator: "\n")) } // 若不需要合并,直接转换: // return conversation.map { Dialogue(speaker: $0.speaker, message: $0.dialogue) } } } // 对应JSON根结构 struct ChapterData: Decodable { let chapter: [ConversationGroup] }
2. 安全的JSON加载与解析
避免强制解包,使用可选绑定和错误处理:
func loadDialogues() throws -> [Dialogue] { guard let path = Bundle.main.path(forResource: "conversation", ofType: "json"), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { throw NSError(domain: "DialogueError", code: 0, userInfo: [NSLocalizedDescriptionKey: "无法加载对话文件"]) } let decoder = JSONDecoder() // 若JSON枚举值和Swift枚举大小写不一致,可开启大小写不敏感解码: // decoder.keyDecodingStrategy = .convertFromSnakeCase let chapterData = try decoder.decode(ChapterData.self, from: data) // 合并所有章节的对话 return chapterData.chapter.flatMap { $0.toDialogues() } } // 使用示例 do { let dialogues = try loadDialogues() for dialogue in dialogues { print("\(dialogue.speaker.rawValue): \(dialogue.messages.joined())") } } catch { print("解析错误:\(error.localizedDescription)") }
关键说明:
- 新增
SingleDialogue临时结构体直接解析JSON单条对话,再转换为自定义Dialogue(支持按角色合并多条消息) - 让
Speaker枚举遵循Decodable协议,直接支持JSON解码 - 用可选绑定替代强制解包,避免崩溃
- 加入错误处理,便于排查加载/解析问题
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

