The case you asking about does not lead to reference cycle.
Reference cycle is only occurs when when 2 or more objects directly or indirectly have pointer (or captured by a block inside a property) to each other :
A->B and B->A (direct)
A->B, B->C, C->A (indirect)
Now what happens with closures that aren't stored as instance properties
Often you may see a view controller that calls some library and provide the handler block.
For example:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
(finished: Bool) -> Void in
// process result of the action
self.showResults()
}
In this case you don't know how long will take this action to complete.
Your block may be submitted into private operation queue. All captured object will be kept alive until this action finishes.
Now the danger part even: if user presses back button (assume the navigation controller is involved) and current view controllers is popped out of navigation stack it will be kept alive because of captured self
even though it will not be displayed on the screen.
This should be rewritten as:
// inside some method of view controller
APIWrapper.sharedInstance().callApiWithHandler(handler: {
[weak self]
(finished: Bool) -> Void in
// process result of the action
self?.showResults()
}
closures that are stored as instance properties of other classes
Similar for this part: you may not be able to control lifecycle of the object that keeps reference to the block.
Object captured by is a implicit reference and may be hard to debug.
To sum up: working with blocks you should always think of how long will this block live and whether it produces cycle or not. It is a good practice to capture objects with weak
/unowned
unless you have good reasons not to do so.