IOSデバイスで読み取り専用のリモートJSONデータを使用するために必要なすべてのステップを簡単に処理するためのソリューションを見つけようとしています。リモートJSONデータの取得、オフライン使用のためのiOSデバイス上のローカルキャッシュへの保存、キャッシュの更新、JSONデータの解析を意味します。最近のすべてのモバイルアプリに共通の要件だと思います。
リモートのJSONファイルを手動でダウンロードし、iOSデバイスのローカルdbまたはファイルに保存し、ネットワークが利用できない場合はローカルストレージから取得するか、そうでなければネットからダウンロードすることが可能であることを知っています。私は今それを手動で行います。 :)しかし、フレームワーク/ライブラリを使用して行うことができる希望はたくさんありますよね?
だから、私は必要なことをほぼすべて行うHanekeSwiftフレームワークを試しましたが、リモートJSON(およびイメージ)のキャッシュのみを行い、キャッシュを更新しません!!私には役に立たない。 AlamofireとSwiftyJSONが存在することも知っていますが、それらの経験はありません。
それを行う方法はありますか?
概要
いい質問です!
AlamofireとSwiftyJSONを組み合わせることで、これを確実に実現できます。私がお勧めするのは、これをできるだけ簡単にするためのいくつかのことの組み合わせです。
JSONを取得するには2つの方法があると思います。
オプション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
と特定の キャッシュポリシー を活用して、目的の処理を実行できる必要があります。
オプション2は非常に多くの作業を必要とし、実際にデータをディスクにキャッシュするキャッシュポリシーを活用する場合、少し奇妙なシステムになります。ダウンロードは、既にキャッシュされたデータをコピーすることになります。リクエストがカスタムURLキャッシュに存在する場合のフローは次のとおりです。
URL
にデータが書き込まれます非常に大きなファイルをダウンロードしない限り、これは非常に無駄です。すべてのリクエストデータをメモリにロードすると、メモリの問題が発生する可能性があります。
キャッシュされたデータを提供された
URL
にコピーすることは、おそらくNSInputStreamとNSOutputStreamを介して実装されます。これは、FoundationフレームワークによってAppleによって内部的にすべて処理されます。これは、データを移動するための非常にメモリ効率の良い方法です。欠点は、アクセスする前にデータセット全体をコピーする必要があることです。
NSURLCache
ここで非常に役立つもう1つのことは、キャッシュされた応答をNSURLCache
から直接フェッチする機能です。 here にあるcachedReponseForRequest:
メソッドを見てください。
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)
それはあなたがしようとしていることを達成するために必要なすべてのツールをカバーするはずです。正確なソリューションをどのように設計するかは、可能な限り多くの方法があるため、あなた次第です。
以下は、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バージョンです( 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
}
}