Development Tip

iOS Swift에서 원격 JSON 데이터를 로컬 캐시 저장소에 동기화

yourdevel 2020. 12. 5. 10:48
반응형

iOS Swift에서 원격 JSON 데이터를 로컬 캐시 저장소에 동기화


iOS 장치에서 읽기 전용으로 원격 JSON 데이터를 사용하는 데 필요한 모든 단계를 간단하게 처리하는 솔루션을 찾으려고합니다. 원격 JSON 데이터를 가져오고, 오프라인 사용을 위해 iOS 장치의 로컬 캐시에 저장하고, 캐시를 새로 고치고, JSON 데이터를 구문 분석하는 것을 의미합니다. 요즘 모든 모바일 앱에서 매우 일반적인 요구 사항이라고 생각합니다.

원격 JSON 파일을 수동으로 다운로드하고 iOS 장치의 로컬 db 또는 파일에 저장할 수 있으며 네트워크를 사용할 수 없을 때 로컬 저장소에서 가져 오거나 그렇지 않으면 net에서 다운로드 할 수 있다는 것을 알고 있습니다. 지금 수동으로합니다. :) 그러나 프레임 워크 / 라이브러리를 사용하여 희망하는 것은 많은 단계입니다. 그렇지 않습니까?

그래서 나는 필요한 거의 모든 것을 수행하는 HanekeSwift 프레임 워크를 시도했지만 원격 JSON (및 이미지) 캐싱 만 수행하지만 캐시를 새로 고치지 않습니다 !! 나에게는 유용하지 않습니다. Alamofire와 SwiftyJSON이 있다는 것도 알고 있지만 경험이 없습니다.

그 방법에 대한 경험이 있습니까?

요약

  • Swift에서 iOS8 지원을위한 라이브러리 또는 프레임 워크
  • 원격 JSON을 다운로드하고 로컬 캐시에 저장
  • 원본에서 로컬 캐시를 새로 고칠 가능성
  • 좋은 보너스는 쉬운 JSON 구문 분석입니다.

여기에 이미지 설명 입력


좋은 질문입니다!

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 은 확실히 가장 많은 양의 Apple 지원 캐싱을 활용합니다. 나는 당신이하려는 NSURLSessionConfiguration일과 함께 특정 캐시 정책활용하여 원하는 작업을 수행 할 수 있어야한다고 생각합니다.

옵션 2 는 훨씬 많은 양의 작업이 필요하며 실제로 디스크에 데이터를 캐시하는 캐시 정책을 활용하는 경우 약간 이상한 시스템이됩니다. 다운로드는 이미 캐시 된 데이터를 복사하게됩니다. 요청이 사용자 지정 URL 캐시에있는 경우 흐름은 다음과 같습니다.

  1. 다운로드 요청
  2. 요청이 캐시되어 캐시 된 데이터가 NSInputStream에로드됩니다.
  3. URLNSOutputStream을 통해 제공된 데이터에 기록됩니다.
  4. 응답 직렬 변환기는 데이터를 메모리로 다시로드하는 곳에서 호출됩니다.
  5. 그런 다음 SwiftyJSON을 사용하여 데이터를 모델 객체로 파싱합니다.

매우 큰 파일을 다운로드하지 않는 한 이것은 매우 낭비입니다. 모든 요청 데이터를 메모리에로드하면 잠재적으로 메모리 문제가 발생할 수 있습니다.

제공된 데이터에 캐시 된 데이터를 복사하는 URL것은 NSInputStream 및 NSOutputStream을 통해 구현 될 가능성이 높습니다. 이것은 모두 Foundation 프레임 워크에 의해 Apple에서 내부적으로 처리됩니다. 이것은 데이터를 이동하는 매우 메모리 효율적인 방법이어야합니다. 단점은 액세스하기 전에 전체 데이터 세트를 복사해야한다는 것입니다.

NSURLCache

One other thing that may be very useful here for you is the ability to fetch a cached response directly from your NSURLCache. Take a look at the cachedReponseForRequest: method which can be found here.

SwiftyJSON

The last step is parsing the JSON data into model objects. SwiftyJSON makes this very easy. If you're using Option 1 from above, then you could use the custom response serializer in the Alamofire-SwiftyJSON. That would look something like the following:

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .responseSwiftyJSON { (request, response, json, error) in
             println(json)
             println(error)
         }

Now if you used Option 2, you'll need to load the data from disk, then initialize a SwiftyJSON object and begin parsing which would look something like this:

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 버전입니다 ( 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

    }
}

참고 URL : https://stackoverflow.com/questions/28418035/synchronizing-remote-json-data-to-local-cache-storage-in-ios-swift

반응형