2010-12-27 2 views
12

오브젝트 묶음의 메모리 내 캐시를 유지해야하는 앱을 작성하고 있지만, 그럴 필요는 없습니다. 그래서 NSCache를 사용하여 모든 것을 저장하려고합니다. . 그것은 나를 위해 깨끗하게하는 등 돌볼 것 같습니다. 그것은 환상적입니다.NSCache 내용을 디스크에 저장하십시오.

또한 실행 사이에 캐시를 유지하고 싶습니다. 따라서 캐시 데이터를 디스크에 기록해야합니다. NSCache 내용을 plist 또는 다른 것으로 저장하는 쉬운 방법이 있습니까? 아마도 NSCache 이외의 것을 사용하여 이것을 수행하는 더 좋은 방법이 있을까요?

이 응용 프로그램은 아이폰에있을 것입니다, 그래서 난 단지 아이폰 OS에서 사용할 수있는 클래스 4+뿐 아니라 OS X의

감사해야합니다!

답변

13

나는 객체의 무리의 메모리 캐시를 을 유지해야하는 응용 프로그램을 쓰고 있어요,하지만 그건 내가 저장 NSCache 를 사용하여 계획입니다 밖으로 손으로하지 않습니다 모든.나를 위해 퍼지 등 돌봐 것 같습니다, 환상적입니다. 또한 캐시 사이에 캐시를 유지하고 싶습니다. 따라서 디스크에 캐시 데이터를 으로 작성해야합니다. NSCache 내용을 쉽게 저장할 수 있습니까 을 plist 또는 다른 것으로 만드시겠습니까? NSCache 이외의 것을 사용하여 이것을 수행하는 더 나은 방법이 있습니까?

정확히 CoreData가 정확히 무엇을 설명했는지, 퍼지 및 잘라내 기 기능이있는 객체 그래프의 지속성

NSCache은 지속성을 지원하도록 설계되지 않았습니다.

핵심 데이터를 사용하는 대신 plist 형식을 사용하도록 제안했다면 개념적 차이가 크지 않을 것입니다.

+0

작성한 거의 모든 데이터베이스 앱에서 핵심 데이터를 사용했지만 가장 적합하지 않은 것처럼 보입니다. 캐시를 사용하여 API 결과를 저장하고 실행시 및 이미로드 된 항목을로드 할 때 앱을 지루하게 유지합니다. 핵심 데이터 데이터베이스가 손에 들고 성장하는 것에 대해 걱정하고 있습니다. 핵심 데이터가 "임시"데이터를 캐싱하는 데 가장 잘 사용되는 것처럼 보이지 않습니다. 필자가 필요로하는 지속성은 기본적으로 필자가 필요로하는 메모리 내 캐싱 기능의 2 차 기능이며, 이것이 NSCache를 향한 것입니다. –

+0

예 - 당신의 수수께끼를 볼 수 있습니다. NSCoding은 구현하기가 어렵지 않습니다. 언제나 그 길로 갈 수 있습니다. 그렇다면 캐시의 영구 버전을 작성/업데이트 할시기가됩니다. 내 경험상, 모든 복잡성을 지닌 지속성 휠을 다시 발명하는 길을 향해가는 것은 꽤 쉽습니다. 그리고 물론, 최고의 성능을 발휘하는 응용 프로그램이 먼저 제공됩니다. ;) – bbum

+0

@CoryImdieke, 우리는 지금 같은 상황에 직면 해 있으며 NSCache를 사용할 계획입니다. 그냥 어떤 솔루션을 선택했는지 궁금하십니까? – Koolala

9

사용 TMCache (https://github.com/tumblr/TMCache). NSCache와 비슷하지만 지속성 및 캐시 제거 기능이 있습니다. Tumblr 팀 글

+1

불행히도, 더 이상 적극적으로 관리되지 않습니다./ – manicaesar

+0

이제 가장 좋은 대답은 CoreData 또는 Realm입니다. Coredata가 가장 표준화 된 영역으로 배우기가 더 쉽습니다. –

0

때때로 코어 데이터를 처리하지 않고 캐시 내용을 디스크에 저장하지 않는 것이 더 편리 할 수 ​​있습니다. NSKeyedArchiverUserDefaults으로이를 수행 할 수 있습니다 (아래 코드 예제에서 Swift 3.0.2를 사용하고 있습니다).

먼저하자 추상적 인 NSCache에서는 우리가 프로토콜을 따르는 캐시를 지속 할 수 있도록하려는 상상 :

protocol Cache { 
    associatedtype Key: Hashable 
    associatedtype Value 

    var keys: Set<Key> { get } 

    func set(value: Value, forKey key: Key) 

    func value(forKey key: Key) -> Value? 

    func removeValue(forKey key: Key) 
} 

extension Cache { 
    subscript(index: Key) -> Value? { 
     get { 
      return value(forKey: index) 
     } 
     set { 
      if let v = newValue { 
       set(value: v, forKey: index) 
      } else { 
       removeValue(forKey: index) 
      } 
     } 
    } 
} 

Key 관련된 유형은 그 Set 형식 매개 변수에 대한 요구 사항이기 때문에 Hashable 수 있습니다.

다음으로 우리는 헬퍼 클래스 CacheCoding를 사용하여 Cache에 대한 NSCoding을 구현해야한다 : 여기

private let keysKey = "keys" 
private let keyPrefix = "_" 

class CacheCoding<C: Cache, CB: Builder>: NSObject, NSCoding 
where 
    C.Key: CustomStringConvertible & ExpressibleByStringLiteral, 
    C.Key.StringLiteralType == String, 
    C.Value: NSCodingConvertible, 
    C.Value.Coding: ValueProvider, 
    C.Value.Coding.Value == C.Value, 
    CB.Value == C { 

    let cache: C 

    init(cache: C) { 
     self.cache = cache 
    } 

    required convenience init?(coder decoder: NSCoder) { 
     if let keys = decoder.decodeObject(forKey: keysKey) as? [String] { 
      var cache = CB().build() 
      for key in keys { 
       if let coding = decoder.decodeObject(forKey: keyPrefix + (key as String)) as? C.Value.Coding { 
        cache[C.Key(stringLiteral: key)] = coding.value 
       } 
      } 
      self.init(cache: cache) 
     } else { 
      return nil 
     } 
    } 

    func encode(with coder: NSCoder) { 
     for key in cache.keys { 
      if let value = cache[key] { 
       coder.encode(value.coding, forKey: keyPrefix + String(describing: key)) 
      } 
     } 
     coder.encode(cache.keys.map({ String(describing: $0) }), forKey: keysKey) 
    } 
} 

:

  • CCache을 준수 유형입니다.NSCoder.encode(forKey:) 방법 키 매개 변수를 수용 String 때문에 String로 전환 될
    • 스위프트 CustomStringConvertible 프로토콜 :
    • C.Key 연관된 유형에 부합한다. 인코딩시 사용 된 NSCoder 키에서 디코딩하는 동안 추출 할 수있는 방법이 없기 때문에
    • 스위프트 ExpressibleByStringLiteral 프로토콜은 우리가 keysNSCoder[String]Set<Key>을 변환하고 저장해야 Set<Key>
  • 다시 [String]를 변환하는 사물. 그러나 캐시에 키가 keys 인 항목이있을 때 캐시 키를 keys 키와 구별하기 위해 캐시 키 앞에 _을 접두어로 붙이는 경우가 있습니다. 당신이 NSCoding 인스턴스에서 다시 값을 얻을 필요가 있기 때문에

    protocol NSCodingConvertible { 
        associatedtype Coding: NSCoding 
    
        var coding: Coding { get } 
    } 
    
  • Value.Coding있다가 ValueProvider 프로토콜을 준수하기 :

  • C.Value 관련된 유형은 값에서 NSCoding 인스턴스를 캐시에 저장 얻을 NSCodingConvertible 프로토콜을 준수해야한다 :

    protocol ValueProvider { 
        associatedtype Value 
    
        var value: Value { get } 
    } 
    
  • C.Value.Coding.ValueC.Value은 동일해야 becau 우리가 NSCoding 인스턴스를 얻는 값은 인코딩 할 때 디코딩 할 때 NSCoding에서 되돌아 오는 값과 동일한 유형이어야합니다.

    protocol Builder { 
        associatedtype Value 
    
        init() 
    
        func build() -> Value 
    } 
    

다음의가 NSCacheCache 프로토콜을 준수합시다 :

  • CB

    Builder 프로토콜을 준수하고 C 유형의 캐시 인스턴스를 생성하는 데 도움이되는 유형입니다. 여기에 문제가 있습니다. NSCacheNSCoder과 동일한 문제가 있습니다. 저장된 개체의 키를 추출하는 방법을 제공하지 않습니다. 이 문제를 해결하는 방법은 세 가지가 있습니다

      Set를 개최 NSCache 대신 사방을 사용합니다
    1. 사용자 정의 유형 랩 NSCache :

      class BetterCache<K: AnyObject & Hashable, V: AnyObject>: Cache { 
          private let nsCache = NSCache<K, V>() 
      
          private(set) var keys = Set<K>() 
      
          func set(value: V, forKey key: K) { 
           keys.insert(key) 
           nsCache.setObject(value, forKey: key) 
          } 
      
          func value(forKey key: K) -> V? { 
           let value = nsCache.object(forKey: key) 
           if value == nil { 
            keys.remove(key) 
           } 
           return value 
          } 
      
          func removeValue(forKey key: K) { 
           return nsCache.removeObject(forKey: key) 
          } 
      } 
      
    2. 을 여전히 다음 어딘가에 NSCache을 통과해야하는 경우 위와 동일한 작업을 Objective-C로 확장하려고 시도 할 수 있습니다. BetterCache.

    3. 다른 캐시 구현을 사용하십시오.

    이제 Cache 프로토콜을 준수하는 유형이므로 사용 준비가 완료되었습니다.

    class Book { 
        let title: String 
    
        init(title: String) { 
         self.title = title 
        } 
    } 
    
    class BookCoding: NSObject, NSCoding, ValueProvider { 
        let value: Book 
    
        required init(value: Book) { 
         self.value = value 
        } 
    
        required convenience init?(coder decoder: NSCoder) { 
         guard let title = decoder.decodeObject(forKey: "title") as? String else { 
          return nil 
         } 
         print("My Favorite Book") 
         self.init(value: Book(title: title)) 
        } 
    
        func encode(with coder: NSCoder) { 
         coder.encode(value.title, forKey: "title") 
        } 
    } 
    
    extension Book: NSCodingConvertible { 
        var coding: BookCoding { 
         return BookCoding(value: self) 
        } 
    } 
    

    일부 가독성을위한 typealiases :

    typealias BookCache = BetterCache<StringKey, Book> 
    typealias BookCacheCoding = CacheCoding<BookCache, BookCacheBuilder> 
    

    그리고 빌더 우리가 Cache를 인스턴스화하는 데 도움이 될 것입니다

    는 이제 우리가 그 유형의 캐시와 NSCoding에 저장할 경우 유형 Book을 정의 할 수 예 :

    class BookCacheBuilder: Builder { 
        required init() { 
        } 
    
        func build() -> BookCache { 
         return BookCache() 
        } 
    } 
    

    테스트 :

    let cacheKey = "Cache" 
    let bookKey: StringKey = "My Favorite Book" 
    
    func test() { 
        var cache = BookCache() 
        cache[bookKey] = Book(title: "Lord of the Rings") 
        let userDefaults = UserDefaults() 
    
        let data = NSKeyedArchiver.archivedData(withRootObject: BookCacheCoding(cache: cache)) 
        userDefaults.set(data, forKey: cacheKey) 
        userDefaults.synchronize() 
    
        if let data = userDefaults.data(forKey: cacheKey), 
         let cache = (NSKeyedUnarchiver.unarchiveObject(with: data) as? BookCacheCoding)?.cache, 
         let book = cache.value(forKey: bookKey) { 
         print(book.title) 
        } 
    } 
    
  • 0

    AwesomeCache을 시도해야합니다. 주요 기능 :

    do { 
        let cache = try Cache<NSString>(name: "awesomeCache") 
    
        cache["name"] = "Alex" 
        let name = cache["name"] 
        cache["name"] = nil 
    } catch _ { 
        print("Something went wrong :(") 
    } 
    
    :
    • 스위프트
    • 에 서면에 디스크 하나의 객체

    예 만료 최대의 성능과 지원을 NSCache 바탕으로 캐싱

  • 에 사용
  • 관련 문제