You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI国旗问答App:国旗存储方案选择与JSON解析问题求助

SwiftUI国旗问答App:国旗存储方案选择与JSON解析问题求助

嘿,作为SwiftUI新手能自己动手做国旗问答App已经很棒啦!别担心,这些问题都是新手入门时很常见的,我来帮你一步步梳理~

一、国旗存储方案怎么选?

针对你的需求,三种方案各有优劣,适合不同阶段:

  • 本地Asset文件夹存储:最适合新手练手,操作简单,不需要网络就能加载国旗,速度快。缺点是如果以后要新增/修改国旗,必须更新App版本。如果你的题库一开始就固定,这个方案最省心。
  • API在线获取:就是你现在选的方式,优点是不用把几百张国旗打包进App,能大幅减小安装包体积,而且国旗数据可以动态更新(比如网站加了新国旗)。但依赖网络,没网的时候就用不了,适合想练习网络请求、后续打算扩展功能的情况。
  • Firebase这类后端服务:如果以后想加用户排行榜、自定义题库、成绩同步这类功能,Firebase确实好用,但初期练手没必要急着上——先把核心的问答功能跑通,等需要扩展再考虑也不迟。

二、你的JSON解析问题怎么解决?

你现在的代码和目标JSON格式不匹配,所以解析会出问题。先看一下目标JSON的结构:它是一个[String: String]的字典,键是国旗的缩写(比如"ad"),值是国家名称(比如"Andorra")。我们可以直接把它解码成字典,再转换成自定义的Flag结构体。

第一步:简化Flag结构体

没必要把flagLink存在结构体里,用计算属性动态生成更合理,这样还能避免冗余数据:

import Foundation
import SwiftUI

struct Flag: Identifiable {
    let shortName: String  // 国旗缩写,比如"ad"
    let name: String       // 国家名称,比如"Andorra"
    let id = UUID()        // 符合Identifiable协议的唯一标识
    
    // 动态生成国旗图片链接
    var flagLink: String {
        "https://flagcdn.com/w320/\(shortName).png"
    }
}

第二步:修正JSON请求与解析逻辑

把原来的getJSON改成带回调的函数,方便在SwiftUI视图里处理返回的国旗数据:

func fetchFlags(completion: @escaping ([Flag]?) -> Void) {
    guard let url = URL(string: "https://flagcdn.com/fr/codes.json") else {
        print("无效的URL,请检查链接")
        completion(nil)
        return
    }
    
    URLSession.shared.dataTask(with: url) { data, response, error in
        // 先处理错误情况
        if let error = error {
            print("网络请求出错:\(error.localizedDescription)")
            completion(nil)
            return
        }
        
        guard let data = data else {
            print("未获取到有效数据")
            completion(nil)
            return
        }
        
        do {
            // 直接解码成[String: String]类型的字典
            let flagDictionary = try JSONDecoder().decode([String: String].self, from: data)
            // 把字典转换成Flag数组
            let flags = flagDictionary.map { keyValue in
                Flag(shortName: keyValue.key, name: keyValue.value)
            }
            // 通过回调返回结果
            completion(flags)
        } catch {
            print("JSON解析失败:\(error.localizedDescription)")
            completion(nil)
        }
    }.resume()
}

第三步:在SwiftUI视图里使用

你可以用@State属性存储国旗数组,在视图出现时调用fetchFlags,然后随机选择国旗展示:

struct FlagQuizView: View {
    @State private var allFlags: [Flag] = []
    @State private var currentFlag: Flag?
    
    var body: some View {
        VStack(spacing: 20) {
            // 展示当前选中的国旗
            if let flag = currentFlag {
                AsyncImage(url: URL(string: flag.flagLink)) { image in
                    image.resizable()
                        .scaledToFit()
                        .frame(height: 200)
                } placeholder: {
                    ProgressView("加载中国旗...")
                }
                
                Text(flag.name)
                    .font(.title)
                    .bold()
            } else {
                Text("点击按钮开始游戏")
                    .font(.headline)
            }
            
            // 随机选择国旗的按钮
            Button("随机出题") {
                currentFlag = allFlags.randomElement()
            }
            .buttonStyle(.borderedProminent)
            .disabled(allFlags.isEmpty)  // 没加载完数据时按钮禁用
        }
        .padding()
        .onAppear {
            // 视图出现时获取国旗数据
            fetchFlags { fetchedFlags in
                if let flags = fetchedFlags {
                    // 回到主线程更新UI
                    DispatchQueue.main.async {
                        allFlags = flags
                    }
                }
            }
        }
    }
}

这样修改后,你就能成功获取国旗数据,随机展示国旗和对应的国家名称啦!

慢慢来,新手遇到JSON解析和网络请求的问题很正常,多试几次就能掌握啦~

备注:内容来源于stack exchange,提问作者axeeeeelt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 14:14:51