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

如何在App中全局保存并访问从服务器获取的数据?

嘿,我来给你梳理几种在iOS App里全局保存和访问从服务器获取的Service数据的常用方案,你可以根据自己的App规模和需求来选择:

方案1:单例模式(Singleton)

这是最直接的全局数据管理方式,创建一个全局唯一的实例来存储数据,任何地方都能直接访问。

先写一个数据管理类:

class DataManager {
    // 全局唯一实例
    static let shared = DataManager()
    
    // 存储你的Service数据
    var services: [Service] = []
    
    // 私有化初始化方法,防止创建多个实例
    private init() {}
}

然后在你的makeGetCall方法里,获取到数据后赋值给单例的属性:

func makeGetCall() {
    let todoEndpoint: String = "http://web.src01.view.beta.is.sa/public/api/services"
    guard let url = URL(string: todoEndpoint) else {
        print("Error: cannot create URL")
        return
    }
    let urlRequest = URLRequest(url: url)
    
    let task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
        guard let data = data else {
            print("Error: No data returned")
            return
        }
        do {
            // 解析数据
            let services = try JSONDecoder().decode([Service].self, from: data)
            // 赋值给全局单例(注意回到主线程更新)
            DispatchQueue.main.async {
                DataManager.shared.services = services
                // 可选:发送通知告知其他页面数据已更新
                NotificationCenter.default.post(name: NSNotification.Name("ServicesUpdated"), object: nil)
            }
        } catch let error {
            print("Error decoding: \(error)")
        }
    }
    task.resume()
}

之后在App的任何地方,你都可以这样访问数据:

let allServices = DataManager.shared.services

小提醒:如果涉及多线程操作数据,记得加线程锁(比如用串行DispatchQueue),避免数据竞争问题。

方案2:SwiftUI专属——ObservableObject + EnvironmentObject

如果你的项目是用SwiftUI开发的,这个方案更贴合框架,还能自动触发视图刷新。

先创建一个视图模型:

class ServiceViewModel: ObservableObject {
    // @Published会在数据变化时自动通知视图刷新
    @Published var services: [Service] = []
    
    func fetchServices() {
        let todoEndpoint: String = "http://web.src01.view.beta.is.sa/public/api/services"
        guard let url = URL(string: todoEndpoint) else {
            print("Error: cannot create URL")
            return
        }
        let urlRequest = URLRequest(url: url)
        
        let task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
            guard let data = data else {
                print("Error: No data returned")
                return
            }
            do {
                let services = try JSONDecoder().decode([Service].self, from: data)
                DispatchQueue.main.async {
                    self.services = services
                }
            } catch let error {
                print("Error decoding: \(error)")
            }
        }
        task.resume()
    }
}

然后在App的入口把这个视图模型注入到环境中:

@main
struct YourApp: App {
    @StateObject private var serviceVM = ServiceViewModel()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(serviceVM) // 注入全局环境
        }
    }
}

之后在任何视图里,你都可以这样获取并使用数据:

struct SomeView: View {
    @EnvironmentObject var serviceVM: ServiceViewModel
    
    var body: some View {
        List(serviceVM.services) { service in
            Text(service.name)
        }
        .onAppear {
            serviceVM.fetchServices()
        }
    }
}
方案3:UserDefaults(适合少量数据持久化)

如果你的Service数据量不大,而且需要重启App后还能保留,UserDefaults是个轻量的选择。首先确保你的Service已经实现完整的Codable(你已经有Decodable,再加Encodable即可):

struct Service : Codable{ 
    let id: Int 
    let name, description: String 
    let createdAt: String? 
    let updatedAt: String? 
}

然后添加保存和读取的方法:

// 保存数据到UserDefaults
func saveServices(_ services: [Service]) {
    do {
        let data = try JSONEncoder().encode(services)
        UserDefaults.standard.set(data, forKey: "SavedServices")
    } catch let error {
        print("Error saving: \(error)")
    }
}

// 从UserDefaults读取数据
func loadServices() -> [Service]? {
    guard let data = UserDefaults.standard.data(forKey: "SavedServices") else {
        return nil
    }
    do {
        return try JSONDecoder().decode([Service].self, from: data)
    } catch let error {
        print("Error loading: \(error)")
        return nil
    }
}

在makeGetCall里获取到数据后,调用saveServices保存,之后在任何地方调用loadServices就能拿到数据啦。

注意:UserDefaults不适合存储大量数据,否则会影响App启动速度和性能。

方案4:Core Data(适合大量/复杂数据持久化)

如果你的Service数据量很大,或者需要做查询、筛选、更新等复杂操作,Core Data是更好的选择。

首先在Core Data里创建对应的实体(比如叫ServiceEntity),属性和你的Service结构体对应:

  • id: Int32
  • name: String
  • description: String
  • createdAt: String?
  • updatedAt: String?

然后把网络请求回来的Service转成ServiceEntity保存:

func saveServicesToCoreData(_ services: [Service]) {
    // 这里的persistentContainer是AppDelegate里的,SwiftUI项目可以用@Environment(\.managedObjectContext)获取上下文
    let context = persistentContainer.viewContext
    
    for service in services {
        let entity = ServiceEntity(context: context)
        entity.id = Int32(service.id)
        entity.name = service.name
        entity.description = service.description
        entity.createdAt = service.createdAt
        entity.updatedAt = service.updatedAt
    }
    
    do {
        try context.save()
    } catch let error {
        print("Error saving to Core Data: \(error)")
    }
}

之后在需要访问数据的地方,通过Core Data的查询请求获取:

func fetchServicesFromCoreData() -> [ServiceEntity]? {
    let context = persistentContainer.viewContext
    let fetchRequest: NSFetchRequest<ServiceEntity> = ServiceEntity.fetchRequest()
    
    do {
        return try context.fetch(fetchRequest)
    } catch let error {
        print("Error fetching from Core Data: \(error)")
        return nil
    }
}

这样你就能全局访问和管理这些持久化的数据了。


内容的提问来源于stack exchange,提问作者Lama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:36:40