はじめに
NSMapTable
は、NSDictionary
に似た辞書型コレクションですが、キーと値の参照の持ち方を自由に設定できる という特徴があります。特に、キャッシュ用途に適しており、メモリ管理を最適化できます。
本記事では、
-
NSMapTable
の基本 - 強参照と弱参照の違い
- キャッシュ管理への活用方法
を解説します。
NSMapTableとは?
NSMapTable
は、NSDictionary
に似た キーと値のペアを管理するコレクション ですが、以下の点が異なります。
✅ NSMapTableの特徴
-
キーと値のメモリ管理をカスタマイズ可能
-
Strong(強参照)
とWeak(弱参照)
を自由に組み合わせられる
-
-
任意のオブジェクト型をキーにできる
-
NSDictionary
はNSObject & NSCopying
に準拠した型しかキーにできないが、NSMapTable
は制限がない
-
-
自動メモリ管理(ARC)に適応
- メモリに余裕がある間はオブジェクトを保持し、不要になると自動解放される
強参照と弱参照の違い
🛠 強参照(Strong Reference)とは?
- あるオブジェクトが 他のオブジェクトを所有している状態
- 参照がある限り、メモリから削除されない
例:強参照の問題(循環参照)
class Person {
var pet: Pet?
}
class Pet {
var owner: Person?
}
let person = Person()
let pet = Pet()
person.pet = pet
pet.owner = person // ⚠️ ここで循環参照が発生!
-
Person
はPet
を所有し、Pet
もPerson
を所有する - どちらも
deinit
されず、メモリリークが発生
➡ 解決策:片方を弱参照(weak)にする
class Pet {
weak var owner: Person?
}
🌱 弱参照(Weak Reference)とは?
- あるオブジェクトを参照していても、そのオブジェクトの生存に影響を与えない
- 参照が
nil
になったら、メモリから自動的に解放される
例:弱参照を使ったメモリ管理
class ViewController: UIViewController {
var cache = NSMapTable<NSString, AnyObject>.strongToWeakObjects()
override func viewDidLoad() {
super.viewDidLoad()
let largeObject = NSObject()
cache.setObject(largeObject, forKey: "key" as NSString)
print(cache.object(forKey: "key" as NSString) != nil) // true
}
}
-
largeObject
はcache
に格納されるが、他に参照がなければdeinit
される
NSMapTableのメモリ管理オプション
オプション | キー | 値 | 使いどころ |
---|---|---|---|
strongToStrongObjects() |
強参照 | 強参照 |
NSDictionary と同じ、データの保持が必要な場合 |
strongToWeakObjects() |
強参照 | 弱参照 | キャッシュ用途、不要になったら自動解放 |
weakToStrongObjects() |
弱参照 | 強参照 | キーが不要になったらエントリを削除 |
weakToWeakObjects() |
弱参照 | 弱参照 | どちらも不要になったら削除、最も軽量なキャッシュ |
NSMapTableをキャッシュに活用する
NSMapTable
はキャッシュ用途に使うことがありm。たとえば、documentCache
を作成し、オブジェクトをメモリに保持しつつ、不要になったら自動解放できます。
📂 documentCache
の例
private var documentCache = NSMapTable<NSString, AnyObject>.strongToWeakObjects()
🚀 使用例:一時的なオブジェクトキャッシュ
class Document {
let name: String
init(name: String) { self.name = name }
}
let cache = NSMapTable<NSString, AnyObject>.strongToWeakObjects()
// オブジェクトをキャッシュ
let doc = Document(name: "MyDoc")
cache.setObject(doc, forKey: "doc1" as NSString)
// キャッシュから取得
if let cachedDoc = cache.object(forKey: "doc1" as NSString) as? Document {
print(cachedDoc.name) // "MyDoc"
}
// `doc` を解放するとキャッシュからも消える
✅ ポイント
-
strongToWeakObjects()
を使用することで、キャッシュに値を格納しても、他に参照がないとdeinit
される。 - メモリが逼迫した際に 自動的に不要なデータが削除される ため、キャッシュとして便利。