SwiftyJSON 代码 - why/how 这行得通吗?

SwiftyJSON code - why/how does this work?

我一直在自学如何使用 SwiftyJSON 和 fab PokeApi.co 解析 JSON 我以为我已经掌握了窍门,直到我尝试获取数组口袋妖怪不同类型的背面。返回的 JSON 如下所示:

...
        ],
        "base_experience": 155,
        "types": [
            {
                "slot": 2,
                "type": {
                    "url": "https://pokeapi.co/api/v2/type/3/",
                    "name": "flying"
                }
            },
            {
                "slot": 1,
                "type": {
                    "url": "https://pokeapi.co/api/v2/type/1/",
                    "name": "normal"
                }
            }
        ]
    }

我需要在 "types" 和 "type" 中获取 "name" 值的数组。我从这里尝试了很多不同的建议,关于他们 Github 的 SwiftyJSON 指南和其他各种来源,我唯一可以开始工作的是:

        let typesArray = json["types"].arrayValue.map({[=12=]["type"]["name"].stringValue})
        for item in typesArray {
            self.currentPokemon.pokemonTypes.append(item.firstUppercased)
            print("Added \(item)")
        }

我很高兴它能正常工作,但我拼命想着手解析 JSON,但这对我来说毫无意义!任何人都可以向我解释发生了什么事吗?有更清晰/更易读的方法吗?

感谢您的宝贵时间!

JSON

首先要做的事情...我认为您需要确保自己真正理解 JSON,然后才能全神贯注于此处所做的事情。 JSON 对象本质上是一个键/值对象。键是一个字符串,值可以是很多东西:更多 JSON 对象的数组,甚至像字符串一样简单。

最佳实践

所以当我必须通过 JSON 解析任何响应时,我喜欢做的一件事是创建一个字符串枚举,它将包含 json 中的所有 "Keys" .请注意,如果您没有为任何情况分配一个值并且类型为 String 当您执行 pokemonApiParams.name.rawValue 它将自动 return stringified 版本你的情况!

enum pokemonApiParams: String {
    case baseExperience
    case types
    case slot
    case type
    case url
    case name
}

现在,当您使用 JSON 时,您可以使用此枚举来帮助使事情变得更清楚。如果您的 API 响应曾经更改过密钥,这尤其好。您可以只更改枚举值,一切都会起作用!这是 "best practice" 的另一个原因是它从您的代码中删除了这些 "magic strings" 并将所有内容保存在一个后勤位置,您以后可以参考!

// This would give you 155 in your example
json[pokemonApiParams.baseExperience.rawValue]

完成您的示例

现在是您难以理解的部分。

首先让我们逐步重建您的 "types array"...

let typesArray = json[pokemonApiParams.types.rawValue]

这家伙创建了一个 json 对象,其中包含您响应中的 "types" 数组。基本的 SwiftyJSON 对象很棒,但您可以在此处更具体一点以获得更多用法,因此您的示例使用 .arrayValue.

的原因
let typesArray = json[pokemonApiParams.types.rawValue].arrayValue

现在我们有一个 JSON 数组对象,我们可以使用各种不同的循环函数遍历它。但是接下来您将使用 .map 函数。习惯了再用,这家伙超级好用!

了解 .map

基本上我们可以将数组中的每个元素映射为其他元素,在这种情况下,我们使用简写来遍历数组并仅获取每种类型的 "name" 属性。所以我们从 [JSON] -> String.

映射

$0 就是我说的 shorthand。将其想象为 for 循环中的索引。 map 函数将遍历整个数组,$0 是数组中正在查看的对象。

也请查看 map 文档!

综合起来

查看您的回复,每个 types 对象都有一个 slot 和一个 type

所以回到你的例子(但使用我们的枚举!):

let typesArray = json[pokemonApiParams.types.rawValue].arrayValue
    .map {
        [=14=][pokemonApiParams.type][pokemonApiParams.name.rawValue].stringValue
    }

现在您的 typesArray 是一个字符串数组。另一种写法(这样会更清楚一些,也可能更容易理解)是:

let typesArray = json[pokemonApiParams.types.rawValue].arrayValue
    .map { (types: JSON) -> String in
        types[pokemonApiParams.type.rawValue][pokemonApiParams.name.rawValue].stringValue
    }

这更清楚,因为我们必须指定我们的对象(类型)而不是使用 $0 shorthand 并且我们指定我们是什么 returning(字符串)。

希望这一切都是正确和清楚的!

祝你编码愉快,赶快赶上他们吧!