For classes, closures provide a mechanism to increment a reference count, thus "keeping the object alive".
Maybe you're okay with just capturing someProperty. Maybe not! The compiler doesn't know if you're using a closure in order to increment the reference, so it makes you be explicit about your intentions.
Not only is that a non-issue with structs, but so is the possibility of mutation, which is strictly disallowed.
Let's say you wanted anotherMethod to allow mutation of any kind, in a struct. You could start by marking it as mutating…
struct SomeStruct {
func someMethod(completion: (() -> Void)?) {}
mutating func anotherMethod() {
someMethod {
self
}
}
}
…but no, that's an error:
Escaping closure captures mutating 'self' parameter
Capture self, though…
mutating func anotherMethod() {
someMethod { [self] in
self
}
}
…and that's fine.
And it's also the only option Swift allows. When you use an escaping closure from within a struct, you can only use an immutable capture of an instance. i.e. [self] in is implicit, for nonmutating methods.
This can yield unexpected results. Be careful.
struct SomeStruct {
var someProperty = 1
func anotherMethod() {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print(someProperty)
}
}
}
var s = SomeStruct()
s.anotherMethod() // 1, even though it's printed after the following reassignment
s.someProperty = 2
s.anotherMethod() // 2
I think it helps to think about what method syntax is shorthand for.
s.anotherMethod()
is really
SomeStruct.anotherMethod(s)()
You can visualize the immutability there, because there's no &.