我正在尝试找到解决方案,以简单处理iOS设备上只读消耗远程JSON数据的所有必要步骤。这意味着获取远程JSON数据,存储到iOS设备上的本地缓存以供脱机使用,刷新缓存,解析JSON数据。我认为现在所有移动应用都是非常普遍的要求。
我知道可以手动下载远程JSON文件,将其存储到iOS设备上的本地数据库或文件中,当网络不可用时,从本地存储中获取它,否则从网上下载。我现在手动完成。 :)但是很多步骤希望通过使用框架/库可以做到,不是吗?
所以我尝试了几乎所有我需要的HanekeSwift框架,但它只缓存远程JSON(和图像),但不刷新缓存!这对我没用。我也知道存在Alamofire和SwiftyJSON,但我对它们没有任何经验。
你有任何经验吗?
摘要的
答案 0 :(得分:39)
很棒的问题!
您可以通过Alamofire和SwiftyJSON的组合来完成此任务。我建议的是将几件事情结合起来,尽可能简化。
我认为您有两种获取JSON的方法。
选项1
// 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 肯定会利用Apple支持的最大缓存量。我认为,通过你想要做的事情,你应该能够利用NSURLSessionConfiguration
和特定的cache policy来完成你想要做的事情。
选项2 将需要更多的工作,如果您利用实际缓存磁盘上数据的缓存策略,将会是一个奇怪的系统。下载最终将复制已缓存的数据。如果您的请求存在于自定义URL缓存中,那么这就是流程。
URL
除非您下载非常大的文件,否则这非常浪费。如果将所有请求数据加载到内存中,则可能会遇到内存问题。
将缓存数据复制到提供的
URL
很可能是通过NSInputStream和NSOutputStream实现的。这一切都由Apple在Foundation框架内部处理。这应该是一种非常有效的内存移动数据的方法。缺点是您需要复制整个数据集才能访问它。
<强> NSURLCache 强>
对您而言,另一件可能非常有用的功能是能够直接从您的NSURLCache
获取缓存响应。查看可以找到的cachedReponseForRequest:
方法here。
<强> SwiftyJSON 强>
最后一步是将JSON数据解析为模型对象。 SwiftyJSON让这很容易。如果您使用上面的选项1 ,那么您可以在Alamofire-SwiftyJSON中使用自定义响应序列化程序。这看起来像下面这样:
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)
这应该涵盖您应该完成所尝试的所有工具。你如何构建精确的解决方案当然取决于你,因为有很多可能的方法来做到这一点。
答案 1 :(得分:3)
下面是我用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()
}
}
}
答案 2 :(得分:1)
这是基于Charl答案的 Swift 3 版本(使用SwiftyJSON和Alamofire):
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
}
}