如何在App中全局保存并访问从服务器获取的数据?
嘿,我来给你梳理几种在iOS App里全局保存和访问从服务器获取的Service数据的常用方案,你可以根据自己的App规模和需求来选择:
这是最直接的全局数据管理方式,创建一个全局唯一的实例来存储数据,任何地方都能直接访问。
先写一个数据管理类:
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),避免数据竞争问题。
如果你的项目是用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() } } }
如果你的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启动速度和性能。
如果你的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

