As Rob said:
It's really a question of "ownership"
That's very true. 'Strong reference cycle' is all about getting that ownership right.
In the following example, we're not using weak var
. Yet both objects will deallocate. Why?
protocol UserViewDelegate: class {
func userDidTap()
}
class Container {
let userView = UserView()
let delegate = Delegate()
init() {
userView.delegate = delegate
}
deinit {
print("container deallocated")
}
}
class UserView {
var delegate: UserViewDelegate?
func mockDelegatecall() {
delegate?.userDidTap()
}
deinit {
print("UserView deallocated")
}
}
class Delegate: UserViewDelegate {
func userDidTap() {
print("userDidTap Delegate callback in separate delegate object")
}
}
Usage:
var container: Container? = Container()
container?.userView.mockDelegatecall()
container = nil // will deallocate both objects
Memory ownership graph (doesn't have cycle)
+---------+container +--------+
| |
| |
| |
| |
| |
| |
v v
userView +------------------> delegate
In order to create a strong reference cycle, the cycle needs be complete. delegate
needs to point back to container
but it doesn't. So this isn't an issue. But purely for ownership reasons and as Rob has said here:
In an object hierarchy, a child object should not maintain strong references to the parent object. That is a red flag, indicating a strong reference cycle
So regardless of leaking, still use weak
for your delegate objects.
In the following example, we're not using weak var
. As a result neither of the classes will deallocate.
protocol UserViewDelegate: class {
func userDidTap()
}
class Container: UserViewDelegate {
let userView = UserView()
init() {
userView.delegate = self
}
func userDidTap() {
print("userDidTap Delegate callback by Container itself")
}
deinit {
print("container deallocated")
}
}
class UserView {
var delegate: UserViewDelegate?
func mockDelegatecall() {
delegate?.userDidTap()
}
deinit {
print("UserView deallocated")
}
}
Usage:
var container: Container? = Container()
container?.userView.mockDelegatecall()
container = nil // will NOT deallocate either objects
Memory ownership graph (has cycle)
+--------------------------------------------------+
| |
| |
+ v
container userview
^ |
| |
| |
+------+userView.delegate = self //container+------+
using weak var
will avoid the strong reference cycle
protocol MyStructProtocol : class { ... }
, then you can make the delegateweak
. See stackoverflow.com/a/24104371/1271826. – Robweak
will not always cause strong reference cycles, but merely raises that possibility. – Rob