在iOS Swift中将远程JSON数据同步到本地缓存存储
我试图找到一种解决方案,可以简单地处理iOS设备上只读消费远程JSON数据的所有必要步骤。这意味着获取远程JSON数据,存储到iOS设备上的本地缓存以供脱机使用,刷新缓存,解析JSON数据。我认为这是当今所有移动应用的普遍要求 我知道可以手动下载远程JSON文件,将其存储到本地数据库或iOS设备上的文件,当网络不可用时,从本地存储获取它,否则从网络加载它。我现在手动操作。:)但是,希望通过使用框架/库可以完成很多步骤,不是吗 所以我尝试了HanekeSwift框架,它几乎可以做我需要的所有事情,但它只缓存远程JSON(和图像),而不刷新缓存!!这对我没用。我也知道存在Alamofire和SwiftyJSON,但我对它们没有任何经验 你有经验怎么做吗 总结在iOS Swift中将远程JSON数据同步到本地缓存存储,ios,swift,http,caching,alamofire,Ios,Swift,Http,Caching,Alamofire,我试图找到一种解决方案,可以简单地处理iOS设备上只读消费远程JSON数据的所有必要步骤。这意味着获取远程JSON数据,存储到iOS设备上的本地缓存以供脱机使用,刷新缓存,解析JSON数据。我认为这是当今所有移动应用的普遍要求 我知道可以手动下载远程JSON文件,将其存储到本地数据库或iOS设备上的文件,当网络不可用时,从本地存储获取它,否则从网络加载它。我现在手动操作。:)但是,希望通过使用框架/库可以完成很多步骤,不是吗 所以我尝试了HanekeSwift框架,它几乎可以做我需要的所有事情,
- Swift中支持iOS8的库或框架
- 下载远程JSON并存储到本地缓存
- 从其来源刷新本地缓存的可能性
- 很好的好处是容易进行JSON解析
// Create a shared URL cache
let memoryCapacity = 500 * 1024 * 1024; // 500 MB
let diskCapacity = 500 * 1024 * 1024; // 500 MB
let cache = NSURLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "shared_cache")
// Create a custom configuration
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
var defaultHeaders = Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders
configuration.HTTPAdditionalHeaders = defaultHeaders
configuration.requestCachePolicy = .UseProtocolCachePolicy // this is the default
configuration.URLCache = cache
// Create your own manager instance that uses your custom configuration
let manager = Alamofire.Manager(configuration: configuration)
// Make your request with your custom manager that is caching your requests by default
manager.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"], encoding: .URL)
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
// Now parse the data using SwiftyJSON
// This will come from your custom cache if it is not expired,
// and from the network if it is expired
}
选项2
let URL = NSURL(string: "/whereever/your/local/cache/lives")!
let downloadRequest = Alamofire.download(.GET, "http://httpbin.org/get") { (_, _) -> NSURL in
return URL
}
downloadRequest.response { request, response, _, error in
// Read data into memory from local cache file now in URL
}
选项1无疑利用了苹果支持的最大数量的缓存。我认为,通过您正在尝试做的事情,您应该能够利用NSURLSessionConfiguration
和一个特定的配置来完成您想要做的事情
选项2将需要大量的工作,而且如果您利用一个缓存策略在磁盘上实际缓存数据,这将是一个有点奇怪的系统。下载将最终复制已缓存的数据。如果您的请求存在于您的自定义url缓存中,那么流程将是这样的
URL
URL
很可能通过NSInputStream和NSOutputStream实现。这都是由Apple通过基础框架内部处理的。这应该是一种非常节省内存的数据移动方式。缺点是需要先复制整个数据集,然后才能访问它
NSURLCache
另一个可能对您非常有用的功能是直接从NSURLCache
获取缓存响应。查看可以找到的cachedReponseForRequest:
方法
SwiftyJSON
最后一步是将JSON数据解析为模型对象。SwiftyJSON使这变得非常简单。如果您正在使用上面的选项1,则可以在中使用自定义响应序列化程序。这将类似于以下内容:
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.responseSwiftyJSON { (request, response, json, error) in
println(json)
println(error)
}
现在,如果使用选项2,则需要从磁盘加载数据,然后初始化一个SwiftyJSON对象并开始解析,如下所示:
let data = NSData(contentsOfFile: URL.path)!
let json = JSON(data: data)
这应该涵盖所有的工具,你应该需要完成你的尝试。如何构建精确的解决方案当然取决于您,因为有很多可能的方法可以做到这一点。下面是我使用Alamofire和SwiftyJSON缓存请求的代码-我希望它能帮助其他人
func getPlaces(){
//Request with caching policy
let request = NSMutableURLRequest(URL: NSURL(string: baseUrl + "/places")!, cachePolicy: .ReturnCacheDataElseLoad, timeoutInterval: 20)
Alamofire.request(request)
.responseJSON { (response) in
let cachedURLResponse = NSCachedURLResponse(response: response.response!, data: (response.data! as NSData), userInfo: nil, storagePolicy: .Allowed)
NSURLCache.sharedURLCache().storeCachedResponse(cachedURLResponse, forRequest: response.request!)
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling GET on /places")
print(response.result.error!)
return
}
let swiftyJsonVar = JSON(data: cachedURLResponse.data)
if let resData = swiftyJsonVar["places"].arrayObject {
// handle the results as JSON, without a bunch of nested if loops
self.places = resData
//print(self.places)
}
if self.places.count > 0 {
self.tableView.reloadData()
}
}
}
这是一个基于Charl答案的Swift 3版本(使用和):
谢谢你的回答!对我来说唯一可能的解决方案是在本地磁盘上存储数据的选项2。当1。网络连接不可用,2。什么时候?ad1-从缓存加载数据(如果可用),ad2-刷新缓存中的数据?可能是个愚蠢的问题,但这是对的吗?如果网络连接不可用,那么您将在
响应中收到一个网络错误。您当然可以添加逻辑,仅当您有internet连接时才尝试下载数据。至于你的其他问题,我已经对上面的答案做了一些大的更新,内容涉及NSURLCache
和不同的NSURLRequestCachePolicy
s。希望这能让你更好地了解利用苹果现有缓存系统的选择。在我的应用程序中,我会使用选项1和NSURLCache
。我想在没有可用连接时使用缓存响应。在缺少连接的情况下,是否存在一种直接使用缓存而不发出请求的方法?谢谢如果我同时使用这两种东西会发生什么?@cnoon你能解释一下现金数据的有效期是多少吗?它会在服务调用期间自动更新?通过调用动态(不同的请求url和参数)请求,我得到了相同的响应,第一次存储在缓存中。有什么想法吗?@lenooh。是否可以在swift中使用Alamofire离线存储数据3@jayaraj&勒诺。。这是我的代码,。如何在swift 3中实现这种离线存储?是否可以修改缓存数据以在以后更新服务器上的数据?
func getData(){
let query_url = "http://YOUR-URL-HERE"
// escape your URL
let urlAddressEscaped = query_url.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
//Request with caching policy
let request = URLRequest(url: URL(string: urlAddressEscaped!)!, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 20)
Alamofire.request(request)
.responseJSON { (response) in
let cachedURLResponse = CachedURLResponse(response: response.response!, data: (response.data! as NSData) as Data, userInfo: nil, storagePolicy: .allowed)
URLCache.shared.storeCachedResponse(cachedURLResponse, for: response.request!)
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error fetching data from url")
print(response.result.error!)
return
}
let json = JSON(data: cachedURLResponse.data) // SwiftyJSON
print(json) // Test if it works
// do whatever you want with your data here
}
}