我有一个PageViewController,它创建DataViewController的实例,并且此dataViewController需要执行一些(从管理器类)调用的API,然后使用该数据填充其UI。即添加页面后,dataViewController会获取其数据源,并使用该数据源来告诉API获取什么。
问题是,因为我可以添加多个页面,并且我需要例如数据来为每个页面形成图形,所以每次视图控制器加载时都必须进行API调用,我感到这很不方便,而且必须是一种更好的方式,可以在会话的整个生命周期内存储数据。由于dataViewController的每个实例都使用相同的API管理器,因此我刷新它们以清除它们拥有的所有数据,然后再次针对加载的页面启动API调用,这有时可能会混淆数据,从而显示两个页面中的信息混合或显示错误页面上的错误数据。这是我的一个API管理器的示例,该示例使用dataViewController的dataObject获取图表数据:
import Foundation
struct Root: Codable {
let prices: [Price]
}
struct Price: Codable {
let date: Date
let price: Double
}
class CGCharts {
var priceData = [Price]()
var graphPrices: [Double] = []
var graphTimes: [String] = []
static let shared = CGCharts()
var defaultCurrency = UserDefaults.standard.string(forKey: "DefaultCurrency")!
var coin = ""
var currency = ""
var days = ""
enum GraphStatus {
case day, week, month
}
var graphSetup = GraphStatus.day
func getData(arr: Bool, completion: @escaping (Bool) -> ()) {
switch graphSetup {
case .day:
days = "1"
case .week:
days = "14"
case .month:
days = "30"
}
let urlJSON = "https://api.coingecko.com/api/v3/coins/\(coin)/market_chart?vs_currency=\(defaultCurrency)&days=\(days)"
guard let url = URL(string: urlJSON) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let prices = try JSONDecoder().decode(Root.self, from: data).prices
print(prices.first!.date.description(with:.current)) // "Saturday, September 1, 2018 at 6:25:38 PM Brasilia Standard Time\n"
print(prices[0].price)
self.priceData = prices
for element in prices {
self.graphPrices.append(element.price)
}
for element in prices {
self.graphTimes.append(element.date.description(with: nil))
}
completion(arr)
} catch {
print(error)
}
}.resume()
}
func refresh(arr: Bool, completion: @escaping (Bool) -> ()) {
defaultCurrency = UserDefaults.standard.string(forKey: "DefaultCurrency")!
graphPrices = []
graphTimes = []
completion(arr)
}
}
在这里您可以看到我正在获取数据,使用可编码解析,在这种情况下,我发现分离数据的最佳方法是使用两个数组,我基本上希望将2个数组存储在内存中该特定dataObject的数据,以便在页面视图中加载具有相同dataObject的页面时,它将首先检查该数据是否已经存在,并使用该数据,而不是每次都需要获取新信息,而我必须清除该类。希望我有道理,谢谢。
答案 0 :(得分:0)
在对NSCache进行了更多研究之后,我了解到您可以将数据保存到磁盘或缓存中并轻松地再次访问它们。我发现了Saoud M. Rizwan here
制作的这种出色的存储类这使得存储结构超级容易:
var messages = [Message]()
for i in 1...4 {
let newMessage = Message(title: "Message \(i)", body: "...")
messages.append(newMessage)
}
Storage.store(messages, to: .documents, as: "messages.json")
并检索它们:
let messagesFromDisk = Storage.retrieve("messages.json", from: .documents, as: [Message].self)
完美存储来自API的数据,这样您就不必进行太多的API调用,如果您的请求受到限制,这尤其有用。就我而言,我使用该方法检查存储是否存在,是否使用该方法加载数据,如果不存在,则执行api调用,使用此类存储数据,然后再次运行检查以看到数据在那里并使用它,它可能不是最有效的,但它可以工作。
我的例子:
var prices: [Double] = []
var days: [String] = []
var priceData = [Price]()
var graphDataExists = false
func checkGraphStorage() {
if Storage.fileExists("\(dataObject)GraphPrices", in:
Storage.Directory.caches) {
print("UsingSavedData")
self.priceData = Storage.retrieve("\(dataObject)GraphPrices", from:
Storage.Directory.caches, as: [Price].self)
if self.prices.isEmpty {
for element in self.priceData {
self.prices.append(element.price)
}
for element in self.priceData {
self.days.append(element.date.description(with: nil))
graphDataExists = true
}
} else {
}
DispatchQueue.main.async {
self.chartView.animate(xAxisDuration: 4.0)
self.lineChartUpdate(dataPoints: self.days, values: self.prices)
}
} else {
self.prepareGraph(arr: true) { (success) in
}
}
}