A pitfall with value type + escaping closure

I'm refactoring my app to use protocol and value type as much as possible, so I did a lot of experiments to understand how to use them properly. I find a pitfall when using value type and escaping closure together. See code below:

struct S {
    var n: Int
    var callback: (() -> Void)!

    init(_ n: Int) {
        self.n = n
        self.callback = { [self] in
            print(self.n)
        }
    }
}

var s1 = S(1)
s1.n = 2
s1.callback() // It outputs 1, not 2

The issue is different from the one that SE-0035 fixed. In SE-0035 case it's the escaping closure changes its copy. But in this case, it's the original copy that was changed but the escaping closure still uses the old copy.

If I understand it correctly, issue like this is almost unresolvable for value type, because there is no way to reference a single value. There have to be multiple copies of the value in above scenario and hence the inconsistency. If so, isn't value type and escaping closure a bad design that should be avoided? But I can't find any discussion about this. I wonder what's other people's experince on this? Sometimes I think it would be very helpful if Apple or someone with knowledge in this could write a book about value type and protocol programming best practice, the patterns and the scenarios to use them or to not use them.

2 Likes