0

Question: For the case of ()-return closures, is there any way to access a variable that ARC lets live only due to a single strong reference from a closure closing over it? In the example below: accessing bb in the closure.

Below follows an example to show what I mean.


In the Language Reference - Expressions, it reads

Capture Lists

By default, a closure expression captures constants and variables from its surrounding scope with strong references to those values. You can use a capture list to explicitly control how values are captured in a closure.

...

Consider the following example, using a weak and a strong capture of two class type instances

class MyClass {
    var myInt : Int = 0
    func printMyInt() {
        print(myInt)
    }
}

func getClosure(a: MyClass, _ b: MyClass) -> (() -> ()) {
    return { [weak aa = a, bb = b] in
        aa?.printMyInt() ?? print("Lost reference")
        bb.printMyInt()
    }
}

func foo() -> (() -> ()) {
    let a = MyClass()
    let b = MyClass()

    let closure = getClosure(a, b)
    closure() // 0, 0
    a.myInt = 1
    b.myInt = 2
    closure() // 1, 2

    return closure
}

If foo() is called, then at the return of closure, MyClass instances a and b are out of scope. In the closure itself, aa keeps a weak reference to a, so a (memory) will be "destroyed" by ARC, and aa will become nil.

However, since the closure closes over b with a strong reference, ARC will retain the memory for b until the closure itself goes out of scope.

let closure = foo()
closure() // Lost reference, 2 <-- OK, expected
/* 'b' (not the reference, but the object in memory) still lives, but
   cant be explicitly accessed? */

Hence my question: how to access, in this case, bb within the closure.


What I've tried

I've tried without success using Mirror:

var bar = Mirror(reflecting: closure)
print(bar.children.count) // 0

Also, I know we can "access" bb in the example above by adding a return type (MyClass) to the closure, but I'm wondering if we can actually access it without such a workaround (hence the ()-return specific closure in the question above).

Where I've looked prior to posting this question

I've been searching around SO for a possible existing threads that asks and answers this question, but the closest one I found,

don't really answer my question here. (Or perhaps the workarounds in the answers to that question does, and the answer to my question above is "you can't"?)

Community
  • 1
  • 1
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • So basically you want to be able to capture a variable from inside the closure, while outside of the closure? – Cristik Jan 11 '16 at 21:31
  • @Cristik Yes, exactly. – dfrib Jan 11 '16 at 21:32
  • Then I think you're out of luck :) You cannot access variables of an inner scope from an outer scope. Unless you do some memory voodoo - i.e. you know the memory location of the variable an you go straight to that memory location. Although in plain Swift not sure if this is realisable. – Cristik Jan 11 '16 at 21:35
  • 1
    Now the curiosity question: why would you need such a thing? – Cristik Jan 11 '16 at 21:36
  • Yeah I've suspected I'm out of luck, just thought I'd see if any of the more experienced swift users here could come up with something. It's just curious that we have a class instance in the closure that we, initially, can fiddle with, but thereafter loose this ability, meanwhile the closure _instance_ still lives. Now as to why: out of sheer curiosity in the process of learning :) usually google and existing SO posts can help me out understanding the intricacies of swift, but in this case, I'm beat. – dfrib Jan 11 '16 at 21:44
  • 1
    This applies not only to Swift, but to all languages that provide visibility scopes for the declared variables. – Cristik Jan 11 '16 at 21:46
  • 1
    It is somewhat similar to encapsulation - accessing private properties. – Cristik Jan 11 '16 at 21:53
  • This case is, however, somewhat of an in-between the subjects of 1. visibility scopes and 2. accessing properties of an object. The latter case is discussable here as the closure is an instance with contents stored in memory. Your comments probably apply here (encapsulatin), in the end, but I'll see if anyone else can supply additional insights. Thanks for your feedback! – dfrib Jan 11 '16 at 22:00

0 Answers0