Retained Storage Time When Closing Swift

In a WWDC 2014 Advanced Swift conversation, the speaker gave this example of a memoizer function using generics:

func memoize<T: Hashable, U>( body: (T)->U ) -> (T)->U { var memo = Dictionary<T, U>() return { x in if let q = memo[x] { return q } let r = body(x) memo[x] = r return r } } 

I am having problems wrapping my life with memo var. Does every call to memoized fibonacci support a strong reference to it? And if so, how would you free this memory when you're done with it?

+8
generics swift memoization
source share
3 answers

In C / Objective-C Blocks memo terminology, there is __block variable (in Swift you do not need to explicitly write __block to capture variables by reference). This variable can be assigned in a block (closure), and all areas that see this variable will see changes from any other variable (they have a link to the variable). The variable will be valid as long as one block is used (closing), which uses it (there is only one block that uses it in this case) is still alive. After the last block that uses it is freed, the variable goes out of scope. How it works is implementation detail.

If this variable had the type of an object pointer, then the specified object would be saved by any blocks that capture it. However, in this case, the Dictionary variable, the type of structure, which is the type of value. Therefore, memory management does not need to worry. A variable is a struct, and a structure lives as long as the variable. (The structure itself can allocate memory elsewhere and free it in its destructor, but should not be aware of and do not care about this completely internally processed by the structure and the external object.)

Generally, you don’t have to worry about how __block variables work inside. But basically the variable is wrapped in a simplified “object” thing, and the actual “variable” is the field of this “object”, which is controlled by memory by reference counting. The blocks that capture them contain "strong links" to this thing with pseudo objects - when a block is created on the heap (technically, when they are copied from stack blocks to the heap), which uses this __block variable, it increases the reference count; when the block that uses it is freed, it decreases the reference count. When the reference counter goes to 0, this pseudo "object" is freed, first it calls the corresponding destructor for its type of variable.

To answer your question, a “remembered fibonacci function” is a block (closure). And this is what contains a strong link to everything that contains the memo variable. "Calls" do not have strong or weak references to it; when a function is called, it uses the link that the function itself has. The lifetime of the memo variable is the lifetime of the “remembered Fibonacci function” in this case, since this is the only closure that captures this variable.

+12
source share

Each memoize() call will create its own memo variable, independent of other calls. He lives as long as the closure refers to him; when a closure is freed, variables captured by it (in this case, memo ) are also freed.

You can think of it as a structure return, as in this pseudocode:

 struct Closure<T,U> { var memo: Dictionary<T, U> func call(t: T): U { .... } } func memoize<T: Hashable, U>( body: (T)->U ) -> Closure<T,U> { return Closure(memo: Dictionary<T, U>()) } 
+3
source share

The indoor unit (return value) will save the memo, which means that the memo will remain as long as the returned blck is saved.

A new memo instance will be created each time the memoize function is called. Calling the returned block will not create new instances of memo.

All memory will be released when the returned block goes out of scope.

+2
source share

All Articles