Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] NSMapTable, weakCache 개념 (딕셔너리와 차이점, weak reference, thread safe) 본문

iOS 응용 (swift)

[iOS - swift] NSMapTable, weakCache 개념 (딕셔너리와 차이점, weak reference, thread safe)

jake-kim 2023. 8. 25. 01:53

NSMapTable 개념

  • key-value쌍으로 구송하는 컬렉션 타입 중 하나인 Dictionary와 유사하지만 memory 관리를 더욱 디테일하게 처리가 가능한 클래스
  • 딕셔너리는 value type이지만 NSMapTable은 class타입이므로 reference type
  • 딕셔너리는 key-value쌍으로 value에 object를 넣으면 strong reference로 잡히지만, NSMapTable은 통해 weak 설정이 가능
  • NSMapTable은 멀티 스레드 환경에서도 안전하게 사용할 수 있는 thread safe 속성도 가지고 있는 장점이 존재

NSMapTable로 메모리 캐싱 구현

  • NSMapTable의 Value 타입에 사용할 class 타입 CachedObject 정의 하나와 NSMapTable 타입인 cache 변수를 전역적으로 선언
    • NSMapTable을 초기화 할 땐 여러가지 방법이 있는데 대표적인 방법은 strongToWeakObjects() 스태틱 함수 사용
    • strongToWeakObjects: key값은 strong, Value값은 weak로 참조한다는 의미
import Foundation

class CachedObject: NSObject {
    let value: Int
    
    init(value: Int) {
        self.value = value
    }
}

let cache = NSMapTable<NSString, CachedObject>.strongToWeakObjects()

사용하는곳)

  • viewDidLoad에서 cache에 setObject로 값을 세팅하고나서, 이 값들은 전역적으로 저장하는 상태
  • 저장하다가 viewDidLoad에서 removeAll()을 수행
  • viewDidAppear에서 과연 Value타입들이 살아 있는지 확인 > objects들은 메모리 해제 되었는지 확인
class ViewController: UIViewController {
    
    var objects = [CachedObject]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        for i in 1...5 {
            let key = "Key\(i)" as NSString
            let object = CachedObject(value: i)
            objects.append(object)
            cache.setObject(object, forKey: key)
        }

        objects.removeAll()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        for i in 1...5 {
            let key = "Key\(i)" as NSString
            if let cachedObject = cache.object(forKey: key) {
                print("캐시성공 > \(key): \(cachedObject.value)")
            } else {
                print("캐시실패 > \(key)")
            }
        }
    }
}
  • viewDidAppear에서 objects들은 메모리 해제된 상태
/*
캐시실패 > Key1
캐시실패 > Key2
캐시실패 > Key3
캐시실패 > Key4
캐시실패 > Key5
*/
  • 만약 cache를 strongToStrongObjects()로 초기화하면 Value타입을 strong reference로 가지고 있으므로 메모리 해제되지 않음
//let cache = NSMapTable<NSString, CachedObject>.strongToWeakObjects()
let cache = NSMapTable<NSString, CachedObject>.strongToStrongObjects()

/*
캐시성공 > Key1: 1
캐시성공 > Key2: 2
캐시성공 > Key3: 3
캐시성공 > Key4: 4
캐시성공 > Key5: 5
*/

정리

  • key-value쌍으로 O(1)로 데이터를 저장하는 자료구조는 Dictionary와 NSMapTable이 존재
    • Dictionrary는 가장 간단한 형태
    • NSMapTable은 weak로 reference를 잡을 수 있어서 메모리 관리 상 디테일하게 처리가 가능
  • 따로 weak와 같은 메모리 관리와 thread safe하게 처리할 필요가 없는 데이터를 관리하고 싶은 경우 Dictionary를 사용하고 메모리 관리가 필요하다면 NSMapTable 사용
  • weak var와 마찬가지로 NSMapTable도 weak reference로 key나 value를 관리하다보면 약간의 오버헤드가 있을 수 있음

* 전체 코드: https://github.com/JK0369/ExNSMapTable

* 참고

https://developer.apple.com/documentation/foundation/nspointerfunctionsoptions

https://developer.apple.com/documentation/foundation/nsmaptable

Comments