NSMapTable中的迭代键永远保留弱值

时间:2019-06-01 09:18:10

标签: ios swift

我正在尝试使用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

用某种方式处理完枚举器后,我是否必须手动清理它?

1 个答案:

答案 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")")
}

在枚举后立即释放对象。

备注: NSEnumeratorSequence,因此您可以使用for循环对其进行枚举:

autoreleasepool {
    let e = map.keyEnumerator()
    for case let key as String in e {
        print(key)
    }
}