编辑:代码工作,问题是与导入的数据集,它没有将空字段分类为数字,而是作为字符串代替。
我的应用程序需要从JSON文件导入类似结构的值,如下所示
[
{
"id": 1,
"string": "Text String",
"int": 6,
"cgfloat": 1.1,
}
]
进口:
id = try container.decode(Int.self, forKey: .id)
string = try container.decode(String.self, forKey: .string)
int = try container.decode(Int.self, forKey: .int)
我不知道如何读取值1.1,Double、Float、CGFloat、Int和String在这里都不起作用。我是否需要更改数据结构,或者是否有办法在Swift中正确解释该值?
这会使应用程序崩溃:
let cgfloat = try container.decode(CGFloat.self, forKey: . cgfloat)
根据要求的完整代码:
struct Monster: Codable, Comparable {
enum MonsterStatus: String, Identifiable, Codable, Hashable {
var id: Self {
return self
}
case Normal = "Normal"
case Attack = "Attack"
case Hit = "Hit"
case Defend = "Defend"
case Dead = "Dead"
}
enum MonsterType: String, Identifiable, Codable, Hashable {
var id: Self {
return self
}
case Undead = "Undead"
case Human = "Human"
case Dinosaur = "Dinosaur"
case Dwarf = "Dwarf"
case Elf = "Elf"
case Wisp = "Wisp"
case Ghost = "Ghost"
case Beast = "Beast"
case Snake = "Snake"
case Giant = "Giant"
case Demon = "Demon"
case Dragon = "Dragon"
case Error = "Error"
}
struct ImagesCatalog: Equatable, Codable {
var Normal: String
var Attack: String
var Defend: String
var Hit: String
var Dead: String
}
static func < (lhs: Monster, rhs: Monster) -> Bool {
return lhs.id < rhs.id
}
static func == (lhs: Monster, rhs: Monster) -> Bool {
return lhs.id == rhs.id
}
var id: Int
let name: String
let image: String = ""
var imagePrefix:String = ""
var strength: Int = 4
var life: Int = 1
var fleeChance: Int = 0
var isBoss: Bool = false
var flying: Bool = false
var mage: Bool = false
var venomous: Bool = false
var giant: Bool = false
var carnivore: Bool = false
var herbivore: Bool = false
var type: MonsterType
var location: HordeGameData.Location
var isFaceUp: Bool = false
var soundAppear: String = "skeletonWalk4.mp3"
var soundHit: String = "skeletonHit1.mp3"
var soundDefend: String = "skeletonEmerge1.mp3"
var soundAttack: String = "skeletonHit4.mp3"
var soundDead: String = "skeletonShatter1.mp3"
var playSound: Bool = true
let images: ImagesCatalog
var imagePic: String
var scaleFactor: CGFloat = 0.5
var active: Bool = false
var slash: Bool = false
var description: String = ""
var status: MonsterStatus = .Normal
func returnColor() -> Color {
if isFaceUp && isBoss {
return .red
} else {
return .red
}
}
func provideID() -> String {
return String(self.id)
}
mutating func playSoundToggle() {
self.playSound.toggle()
}
mutating func reduceStrengthBy(_ amount: Int) {
if strength > amount {
self.strength -= amount
}
}
mutating func defineImage(status: MonsterStatus, slash: Bool) {
self.status = status
switch status {
case .Normal: imagePic = images.Normal
if playSound {
Sound.play(file: self.soundAppear)
}
case .Attack: imagePic = images.Attack
if playSound {
Sound.play(file: self.soundAttack)
}
case .Defend: imagePic = images.Defend
if playSound {
Sound.play(file: self.soundDefend)
}
case .Hit : imagePic = images.Hit
if playSound {
Sound.play(file: self.soundHit)
}
case .Dead : imagePic = images.Dead
if playSound {
Sound.play(file: self.soundDead)
}
}
self.slash = slash
}
mutating func nextImage() {
switch self.status {
case .Normal: defineImage(status: .Attack, slash: false)
case .Attack: defineImage(status: .Defend, slash: false)
case .Defend: defineImage(status: .Hit, slash: false)
case .Hit : defineImage(status: .Dead, slash: false)
case .Dead : defineImage(status: .Normal, slash: false)
}
}
mutating func setID(_ id: Int) {
self.id = id
}
mutating func reduceLife() {
life -= 1
}
mutating func addLife() {
life += 1
}
func provideLife() -> String {
var lifeString = ""
for _ in 0..<life {
lifeString.append("💜")
}
return lifeString
}
///
private enum CodingKeys: String, CodingKey {
case id
case name
case imagePrefix
case strength
case life
case fleeChance
case isBoss
case flying
case mage
case venomous
case giant
case carnivore
case herbivore
case type
case location
case soundAppear
case soundHit
case soundDefend
case soundAttack
case soundDead
case images
case scaleFactor
case description
}
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)
imagePrefix = try container.decode(String.self, forKey: .imagePrefix)
strength = try container.decode(Int.self, forKey: .strength)
life = try container.decode(Int.self, forKey: .life)
fleeChance = try container.decode(Int.self, forKey: .fleeChance)
isBoss = try container.decode(Bool.self, forKey: .isBoss)
flying = try container.decode(Bool.self, forKey: .flying)
mage = try container.decode(Bool.self, forKey: .mage)
venomous = try container.decode(Bool.self, forKey: .venomous)
giant = try container.decode(Bool.self, forKey: .giant)
carnivore = try container.decode(Bool.self, forKey: .carnivore)
herbivore = try container.decode(Bool.self, forKey: .herbivore)
let monsterTypeValue = try container.decode(String.self, forKey: .type)
type = MonsterType(rawValue: monsterTypeValue) ?? .Error
let locationValue = try container.decode(String.self, forKey: .location)
location = HordeGameData.Location(rawValue: locationValue) ?? .Error
soundAppear = try container.decode(String.self, forKey: .soundAppear)
soundHit = try container.decode(String.self, forKey: .soundHit)
soundDefend = try container.decode(String.self, forKey: .soundDefend)
soundAttack = try container.decode(String.self, forKey: .soundAttack)
soundDead = try container.decode(String.self, forKey: .soundDead)
images = .init(Normal: imagePrefix + "Normal",
Attack: imagePrefix + "Attack",
Defend: imagePrefix + "Defend",
Hit: imagePrefix + "Hit",
Dead: imagePrefix + "Dead")
imagePic = imagePrefix + "Normal"
// let stringScale = try container.decode(CGFloat.self, forKey: .scaleFactor)
// print(stringScale)
// scaleFactor = stringScale.CGFloatValue() ?? 0.5
description = try container.decode(String.self, forKey: .description)
print("Monster \(id): \(name) imported")
}
}
解码功能
class MonsterInventory {
static let shared = MonsterInventory()
var staticItems: [Monster] = []
private init() {
self.parseMonsterJson()
}
private func parseMonsterJson() {
guard let monsterJsonFileUrl = Bundle.main.url(forResource: "Monsters", withExtension: "json") else {
fatalError("Unable to find file")
}
do {
let content = try Data(contentsOf: monsterJsonFileUrl)
let jsonDecoder = JSONDecoder()
staticItems = try jsonDecoder.decode([Monster].self, from: content)
} catch let error {
print(error.localizedDescription)
staticItems = []
}
}
func fetchMonsterWithID(_ id: Int) -> Monster {
return staticItems.filter{$0.id == id}.first ?? staticItems.filter{$0.id == 10}.first!
}
func fetchMonsterWithName(_ name: String) -> Monster {
return staticItems.filter{$0.name == name}.first ?? staticItems.filter{$0.id == 10}.first!
}
}
下面是JSON的一个摘录:
[
{
"id": 1,
"name": "Skeleton Warrior",
"strength": 6,
"life": 1,
"fleeChance": 0,
"isBoss": false,
"flying": false,
"mage": false,
"venomous": false,
"giant": false,
"carnivore": false,
"herbivore": false,
"type": "Undead",
"location": "Plains",
"soundAppear": "skeletonWalk4.mp4",
"soundHit": "skeletonHit1.mp3",
"soundDefend": "swordSwoosh2.m4a",
"soundAttack": "swordSwoosh1.m4a",
"soundDead": "skeletonShatter2.mp3",
"imagePrefix": "SkeletonWarrior",
"imageNormal": "SkeletonWarriorNormal",
"imageAttack": "SkeletonWarriorAttack",
"imageDefend": "SkeletonWarriorDefend",
"imageHit": "SkeletonWarriorHit",
"imageDead": "SkeletonWarriorDead",
"scaleFactor": 1.1,
"description": "A weak skeleton fighter."
},
...
]
1条答案
按热度按时间p8h8hvxi1#
我不确定为什么要逐个密钥地解码...我认为您应该创建一个
struct
,除非您真的需要逐个密钥地解码(例如侧翼提到的评论这个答案)。
如果您确实需要逐个键进行解码,则需要提供有关如何解码JSON的更多详细信息
这是适合JSON的结构体
您还可以更改变量名称以遵循camelCase命名。
这就是解码对象的方法。
在本例中,JSON的根是一个数组,因此在这种情况下,我们不使用
Elm.self
,而是使用[Elm].self
解码到数组这样Swift将JSON KeyMap到匹配的变量名(或者使用编码键,就像我在第二个结构体中演示的那样)
这在Playground进行了测试
根据您更新的问题,我现在明白了为什么个别解码,但假设您有问题的关键是
scaleFactor
,这是唯一的浮点数在样本中,您提供的代码工作没有任何问题。现在您可以仔细检查文件的读取是否正确(如果您可以读取文件的其余部分,则可能正确)