Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How NSMapTable works

I'm trying to figure out how NSMapTable works So I'm trying in playground the following code:

class Person {
    var name: String


    init(name: String ) {
        self.name = name
        print("\(name) is being initialized")
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

var hobyePerson : NSMapTable? = NSMapTable<Person, NSMutableString>
(keyOptions: .weakMemory, valueOptions: .weakMemory)

var rob : Person? = Person(name: "Rob Appleseed") // print : Rob Appleseed is being initialized

hobyePerson?.setObject("golf", forKey: rob)
hobyePerson?.count // return : 1


rob = nil // print : Rob Appleseed is being deinitialized
hobyePerson?.count // return : 1 (WHY ???!!!!)

as written in the documentation: "Keys and/or values are optionally held “weakly” such that entries are removed when one of the objects is reclaimed."

why even though I initialized the object so that it has a weak reference to the key-value pair when rob is deallocated, I still have an element in hobyePerson?

like image 994
emacos Avatar asked Oct 27 '17 19:10

emacos


People also ask

What is NSMapTable?

A collection similar to a dictionary, but with a broader range of available memory semantics. iOS 6.0+ iPadOS 6.0+ macOS 10.5+ Mac Catalyst 13.1+ tvOS 9.0+ watchOS 2.0+

Does NSDictionary retain objects?

An NSDictionary will retain it's objects, and copy it's keys. Here are some effects this has had on code I've worked on. Sometimes you get the same object you put in, sometimes not. Immutable objects are optimized to return themselves as a copy .

What is NSDictionary in Swift?

An object representing a static collection of key-value pairs, for use instead of a Dictionary constant in cases that require reference semantics.


2 Answers

NSMapTable's weak behavior options work best when you don't care when keys/values are released, but rather, you do care that the keys/values aren't strongly retained and will be released at some point after the object of interest becomes nil.

Why so?

As a Foundation class, the authors of NSMapTable had to balance both features and performance.

Consequently, as an "optimization" for performance, they chose that weakly referenced objects that become nil are NOT immediately removed from the map table...! Rather, this happens "later" when it can be efficiently done -- such as when the map table internally gets resized, etc.

As @Luke also mentions in his answer, see this excellent writeup about an experiment done on NSMapTable's behavior for more details:

http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/

like image 169
JRG-Developer Avatar answered Sep 24 '22 00:09

JRG-Developer


Yes, this is a strange and unfortunate behavior. This article goes into it in some depth. Although it doesn't explore weak-to-weak specifically, the behavior described is the same. As that author notes, hobyePerson.keyEnumerator().allObjects.count and hobyePerson.objectEnumerator().allObjects.count will contain 0 as expected at the end of all this. He also points out that Apple has sort of documented this behavior in the Mountain Lion release notes.

However, weak-to-strong NSMapTables are not currently recommended, as the strong values for weak keys which get zero’d out do not get cleared away (and released) until/unless the map table resizes itself.

Sorry I don't have a better explanation for you.

like image 45
Luke Avatar answered Sep 26 '22 00:09

Luke