2015-02-09 109 views
55

同步遠程JSON數據到本地緩存存儲我試圖找到簡單的處理解決方案的所有必要步驟只讀消耗在iOS設備上的遠程JSON數據。它意味着獲取遠程JSON數據,存儲到iOS設備上的本地緩存以供離線使用,刷新緩存,解析JSON數據。我認爲現在所有移動應用都是非常普遍的要求。在iOS版雨燕

我知道它是可以手動下載遠程JSON文件,其存儲到本地數據庫或iOS設備上的文件,當網絡不能從本地存儲獲取它,否則從網下載中心它。我現在手動做。 :)但它是很多希望可以通過使用框架/庫來完成的步驟,不是嗎?

所以,我想HanekeSwift框架,做幾乎所有我所需要的,但它只能做緩存遠程JSON(和圖像),但不會刷新緩存!這對我無用。我也知道存在Alamofire和SwiftyJSON,但我沒有任何經驗。

你有什麼經驗該怎麼做?

摘要

  • 庫或框架在斯威夫特iOS8上的支持
  • 下載遠程JSON和存儲到本地緩存
  • 可能性刷新本地緩存從它的起源
  • 不錯的獎金很容易JSON解析

enter image description here

謝謝! Michal

回答

39

好問題!

您可以絕對與Alamofire和SwiftyJSON的組合實現這一點。我會推薦的是幾件事情的組合,以儘可能簡化。

我想你有兩種方法來獲取JSON。

  1. 取內存的JSON數據並使用高速緩存策略
  2. 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肯定利用蘋果的最大負載量緩存。我認爲,通過你想要做的事情,你應該能夠利用NSURLSessionConfiguration和一個特定的cache policy來完成你想要做的事情。

選項2將需要更大的工作量,如果您利用實際緩存磁盤上的數據的緩存策略,則會有點奇怪的系統。下載將最終複製已經緩存的數據。如果您的請求存在於您的自定義網址緩存中,則流程如下所示。

  1. 製作下載請求
  2. 請求被裝入NSInputStream高速緩存,所以緩存數據
  3. 數據通過NSOutputStream寫入提供URL
  4. 響應串被稱爲在這裏裝載數據返回到內存
  5. 然後使用SwiftyJSON將數據解析爲模型對象

This i除非你正在下載非常大的文件,否則很浪費。如果將所有請求數據加載到內存中,則可能會遇到內存問題。

將高速緩存的數據複製到提供的URL很可能通過NSInputStream和NSOutputStream實現。這一切都是由基金會框架在Apple內部處理的。這應該是移動數據的高效內存方式。缺點是您需要複製整個數據集才能訪問它。

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) 

這應該涵蓋所有你需要完成你嘗試的工具。如何構建確切的解決方案當然取決於你,因爲有很多可能的方法來做到這一點。

+0

感謝您的回答!對我來說唯一可行的解​​決方案是將選項2存儲在本地磁盤上。當1.網絡連接不可用時,Alamofire究竟做了什麼?2.什麼時候? ad1 - 從緩存中加載數據(如果可用),ad2 - 刷新緩存中的數據?也許愚蠢的問題,但它是正確的? – kolisko 2015-02-11 19:34:40

+0

如果網絡連接不可用,您將在'response'中收到網絡錯誤。如果你有互聯網連接,你當然可以添加邏輯來嘗試下載數據。至於你的其他問題,我對'NSURLCache'和不同的'NSURLRequestCachePolicy'做了一些大的更新。希望能夠讓您更好地利用已有的蘋果緩存系統的選項。 – cnoon 2015-02-12 06:16:28

+2

在我的應用程序中,我將使用選項1並使用'NSURLCache'。我想在沒有可用連接時使用緩存響應。它是否存在一種直接使用緩存的方式,在沒有請求的情況下,在連接不存在的情況下?謝謝 – 2016-05-04 14:45:55

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() 
      } 
    } 
} 
+0

是否有可能修改緩存的數據以便稍後更新服務器上的數據? – fullMoon 2017-11-08 13:07:09

1

這是一個基於查爾的回答一個斯威夫特3版本(使用SwiftyJSONAlamofire ):

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 

    } 
} 
+0

通過調用動態(不同的請求url和參數)請求,我得到相同的響應,這是第一次存儲在緩存中。任何想法 ? – 2017-03-04 09:24:07

+0

@lenooh。是否有可能使用Alamofire以快速方式存儲數據3 – 2017-05-15 06:44:35

+0

@jayaraj&lenooh ..這是我的代碼,https://ibb.co/nKKXkk。我怎樣才能在swift 3中實現這種離線存儲? – 2017-05-15 07:32:04