我正在尝试使用NSMapTable
弱存储一些由字符串索引的对象实例。
(我的用例是存储一些有关远程服务器的缓存元数据,并让每个活动客户端共享该元数据。当不再有客户端连接到该特定服务器时,应从内存中删除该元数据。)
一切正常,只要我从不遍历键即可。好像,如果我遍历了特定的键,该键的值将永远不会释放。
我设法将其缩小为一个显示问题的小代码段:
import Foundation
class Foobar {
let id: String
init(_ id: String) { print("init \(id)"); self.id = id }
deinit { print("deinit \(id)") }
}
let map = NSMapTable<NSString, Foobar>(keyOptions: .strongMemory, valueOptions: .weakMemory)
func addSome() {
let a = Foobar("a")
let b = Foobar("b")
let c = Foobar("c")
map.setObject(a, forKey: "a")
map.setObject(b, forKey: "b")
map.setObject(c, forKey: "c")
let e = map.keyEnumerator()
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
}
addSome()
print(map.object(forKey: "a") ?? "nil")
print(map.object(forKey: "b") ?? "nil")
print(map.object(forKey: "c") ?? "nil")
如果我注释掉一个或多个e.nextObject()
调用,相应键的值将被正确释放,而map.object(forKey:)
将正确返回nil
。
用某种方式处理完枚举器后,我是否必须手动清理它?
答案 0 :(得分:0)
显然,地图枚举器返回“自动释放”对象-当当前自动释放池的范围离开时,这些对象将被释放。
在iOS或macOS应用程序中,当程序控制返回到主事件循环时会自动发生。无论如何,您都可以使用本地autorelease pool
autoreleasepool {
let e = map.keyEnumerator()
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
print("nextObject: \(e.nextObject() ?? "nil")")
}
在枚举后立即释放对象。
备注: NSEnumerator
是Sequence
,因此您可以使用for循环对其进行枚举:
autoreleasepool {
let e = map.keyEnumerator()
for case let key as String in e {
print(key)
}
}