Capturing self in the block temporarily - swift

Having a runtime error when program is compiled, purposefully the instantiation of SomeObject is short lived but the block getting passed captures the reference, doesn't work in playground but shows the error when the program is compiled and run.
Objective is to hold the reference temporarily of short lived objects SomeObject until callback gets completed.
Edit - if I comment [unowned self] inside go it works, as I believe it creates a strong reference, but hopefully no memory leak there??? (the caller object went out of scope anyway). please confirm that I shouldn't use [unowned self] in here.
import Foundation
class SomeObject {
func go() { //i guess problem is here, it can't find self,
anotherObject.asyncCall({ [unowned self] in //works if i comment this
self.complete()
})
}
func complete() { //can't move this routine inside block, part of parent class api
println("received callback after 5 sec")
}
}
class AnotherObject {
var callback: (() -> ())?
init() {}
func asyncCall(callback: () -> ()) {
self.callback = callback
let delay = 5 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), { [unowned self] in
self.callback!()
})
}
}
var anotherObject = AnotherObject() //not global object but permanent lived
for i in 1...3 { //can't change here, it's part of API that instantiates my objects
var instance = SomeObject() //short lived objects
instance.go()
}

please confirm that I shouldn't use [unowned self] in here
There's no need to concern yourself with memory management merely because an anonymous function mentions self.
If an anonymous function that mentions self is going to be a property of self, then you have a retain cycle and potential memory leak, and you should concern yourself with memory management. You can easily see whether you have a memory leak by implementing your deinit to log; if it doesn't log when you expect this object to be destroyed, it's leaking. If it is leaking, you might try using [weak self], not [unowned self]. unowned is more convenient but it is usable only in very limited circumstances.
However, I see no evidence that the object that's going to retain the callback is the same object that is referred to in it as self. It looks to me more like the opposite: you seem to be using [unowned self] on every anonymous function, apparently without the slightest knowledge of what you are doing. That is extremely dangerous. You should not interfere with memory management unless you have to and unless you know how to. My advice is that you start by deleting every single unowned in your code. Then implement deinit and see if you have any actual leaking objects. I'm betting that you don't.

Related

Swift [weak self] for Dispatching on main in a nested closure

So I read that when running DispatchQueue.main.async { } you don't need to declare [weak self]. However, i joined a new project, and stumbled across this:
public func dispatchOnMain(execute: #escaping () -> Void) {
if Thread.isMainThread {
execute()
return
}
DispatchQueue.main.async(execute: execute)
}
Which is an open global function. From here on, doing something like:
class Foo {
func bar() {
dispatchOnMain {
// Do something
}
}
}
Will this dispatchOnMain { require a weak self? And why / why not?
You're way overthinking this. The need for weak self has nothing to do with what thread you're going to be on, and it has nothing to do with dispatch queues. If you're going to be worrying about weak self every time you see a pair of curly braces, you'll be a nervous wreck. 😃
Weak self has to do with whether there will be a retain cycle. Retain cycles are caused through long term storage of a closure by an object it captures.
Nothing like that is going on here. When you are just saying "perform this action now", regardless of the thread, no retain cycle arises. So no precautions are necessary.

How Unowned reference works with capture variables in Swift

There are a lot of tutorials on ARC. But I am not understanding the clear working of unowned or weak as how the reference captured variables becomes null.
Apple Document :
Define a capture in a closure as an unowned reference when the closure
and the instance it captures will always refer to each other, and will
always be deallocated at the same time.
class RetainCycle {
var closure: (() -> Void)!
var string = "Hello"
init() {
closure = { [unowned self] in
self.string = "Hello, World!"
}
}
}
the closure refers to self within its body (as a way to reference self.string), the closure captures self, which means that it holds a strong reference back to the RetainCycle instance. A strong reference cycle is created between the two. By unowned its breaking reference cycle.
But I want to understand which scenario both will not be mutually deallocated at the same time and Unowned self becomes null just want to crash it.?
As I get, You ask How self can be null while closue is running. If I get this right I can give you a quite similar example this that I have seen before.
I wrote an extension to UIImageView that download image from given link and set itself like this.
public extension UIImageView{
func downloadImage(link: String){
let url = URL(string:link)
URLSession.shared.dataTask(with: url){ [unowned self]
if let image = UIImage(data: data){
DispatchQueue.main.async{
self.image = image
}
}
}
task.start()
}
}
But there was a problem. Downloading an image is a background task. I set completion method to UrlSession and increased its reference count. So, my closure remains even if imageView is deaollecated.
So What happens if I close my viewController that holds my UIImageView, before download completed. It crashes because of imageView is deallocated but closure still remains and tries to reach its image property. As I get, you want to learn this.
I changed unowned reference to weak to solve this problem.
which means that it holds a strong reference back to the RetainCycle instance
This isn't true. It has an unowned reference back to the RetainCycle instance. That's not the same thing as a strong reference.
But I want to understand which scenario both will not be mutually deallocated at the same time and Unowned self becomes nilI just want to crash it.?
Any time closure is captured by something outside of RetainCycle, and so outlives its owner:
var rc: RetainCycle? = RetainCycle() // create an RC
let cl = rc?.closure // Hold onto its closure
rc = nil // Deallocate the RC
cl?() // Access the closure safely, but its reference to `self` is invalid. Crash.
As a rule, closures that involve unowned self should be impossible to reference outside of self. It's sometimes difficult to know this is true. For example, here is a case that recently crashed an app I work on:
var completion: (() -> Void)?
...
DispatchQueue.main.async { [unowned self] in
self.completion()
self.completion = nil
}
This feels fine, but if self is deallocated between the time it enqueues the main-queue block and the time that block runs, boom.
BTW, in this case the right answer would be a regular, strong self. We want the retain loop to keep this object around until its completion handler runs, at which point the block goes away, the reference to self goes away, and self is properly deallocated. So [weak self] is not always the answer, either.

Swift closures causing strong retain cycle with self

I just want to know if I am understanding this correctly or not. So according to the apple docs when you create a closure as a property of a class instance and that closure references self(The class that created the closure property) this would cause a strong retain cycle an ultimately the class nor the closure will ever get released. So in laymen terms that means that if I have a class that has a property and that property is a closure, and once I assign the functionality of that closure within the class that declares the closure property that will cause a strong retain cycle. Heres a quick example of what I mean
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = {
self.dismiss(blahBlahBlah)
}
}
}
This ultimately causes a retain cycle since the closure keeps a strong reference to self, which is the class that creates the closure property. Now to fix this according to apple I would define a capture list like so
class SomeViewController{
let myClosure:()->Void
public func someFunction(){
....bunch of code
myClosure = { [weak self] in
self?.dismiss(blahBlahBlah)
}
}
}
Notice how I put the [weak self] before the in statement. This lets the closure know to only hold a weak reference to self and not a strong reference. IM supposed to use weak when self can out live the closure or unowned when the closure and self live for the same duration.
I got this information from here Automatic Reference Counting and in the Strong Reference Cycles for Closures section of that link, theres this sentence "A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance" Im about 90% sure Im understanding this correctly but theres just that 10% of doubt. So do I have this correct?
The reason why im asking this is because I use callbacks for some of my buttons in my views. And those callbacks call to self but the self in that scenario is the view controller that is responding to the callback not the actual view itself. This is where im doubting myself because I from that sentence I highlighted I don't think I need to put [weak self] on all those button callbacks, but im just making sure. Heres an example of this
class SomeViewController {
let someSubview:UIView
override viewDidLoad() {
//Some Subview has a button and in that view I just have some action that gets fired off calling the callback here in the view controller I don't need to use the [weak self] in this scenario because closure property is not in this class correct?
someSubview.someButtonsCallback = {
....run code then
self?.dismiss(blahBlahBlah)
}
}
Yes, that can still cause a retain cycle.
The simplest retain cycle is 2 objects that each have strong references to each other, but 3-way and larger retain cycles are also possible.
In your case, you have view controller who's view contains a button (a strong reference.) The button has a strong reference to a closure. The closure strongly references the view controller using self. So the view owns the button. The button owns the closure. The closure owns the view controller. If you dismiss the view controller (say it was a modal) then it SHOULD be deallocated. However, since you have this 3-way retain cycle, it won't be deallocated. You should add a deinit method to your view controller with a print statement and try it.
The solution is to add a capture list (The [weak self] bit) just like you did in your first example.
Note that a common pattern is to add a capture list, and then map the weak variable to a strong variable inside the closure:
let myClosure = { [weak self] in
guard let strongSelf = self else { return }
//...
strongSelf.doSomething()
}
That way, if the closure is still active but the object that owns it was released, the guard statement at the beginning detects that self is nil and exits at the beginning of the closure. Otherwise you have to unwrap the optional every time you refer to it.
In certain cases it's also possible that the object in the capture list (self in these examples) could be deallocated in the middle of the closure being executed, which can cause unpredictable behavior. (Gory details: This is only when the closure is run on a different thread than the owner of the object in the capture list, but completion handlers are pretty commonly run on a background thread, so it does happen)
Imagine this:
let myClosure = { [weak self] in
self?.step1() //1
//time-consuming code
self?.property = newValue //2
//more time-consuming code
self?.doSomething() //3
//even more time-consuming code
self?.doSomethingElse() //4
}
With the code above, if the closure is run on a background thread, its possible that self would still be valid at step 1, but by the time you execute step 2, self has been deallocated. The same goes for steps 3 and 4. By adding the guard strongSelf = self else { return } at the beginning of the closure you test at the entry of the closure to make sure self is still valid, and if it is, you make the closure create a strong reference that only lives as long as the closure takes to run, and that prevents self from being deallocated while the closure code is executing.)

Will this cause a retain cycle Swift?

I have this code and I'm questioning if I need to use a capture list to make my reference to self weak.
Right now I'm thinking that getTextFileData and .main.async are static methods, therefore, this will not cause a retain cycle. However, I do access the games property, kinda not sure.
NPWebService.getTextFileData { (games, success) in
if success {
self.games = games
DispatchQueue.main.async {
self.updateUI()
}
}
}
This wouldn’t cause a retain cycle because it looks like a static method on a different type. So the getTextFileData method will temporarily retain the closure you are passing in until any asynchronous work is complete, and the closure will temporarily retain self. But when the work is complete and the closure is done executing, those temporary retains will expire and automatic memory management can clean up as appropriate.
The danger of a retain cycle is when you have a closure the that references / captures self, and self also retains the closure, for example. Like this:
class GameController {
var games: [Game]?
// self retains the closure as a property
let updateClosure:([Game], Bool)->() = {
games, success in
if success {
self.games = games // and the closure captures self. Each retains each other indefinitely, this is a retain cycle and neither this closure nor self will ever be deallocated
}
}
func load() {
NPWebService.getTextFileData(updateClosure)
}
}
So normally weak self or unowned self in closure capture lists are only needed:
if self or something retained by self will be retaining that closure (this is rarely the case when a closure is created locally and transiently at the call site to pass into a method as an argument)
if for non-retain cycle reasons, the desired behavior is to allow self to be deallocated before some asynchronous work is completed, and before the closure is invoked. In this case the closure shouldn’t strongly capture self and instead should weakly capture it and check if it still exists before making use of self when the closure is invoked

Referencing [weak self] as self? inside animateWithDuration causes crash

If I declare [weak self] on a closure and reference self as self? inside UIView.animateWithDuration the app will crash:
someFunc() { [weak self] (success) -> Void in
UIView.animateWithDuration(0.25) {
self?.someView.alpha = 1;
}
}
with a message sent to deallocated instance
but if I optionally unwrap self ahead of time it doesn't
someFunc() { [weak self] (success) -> Void in
if let weakself = self {
UIView.animateWithDuration(0.25) {
weakself.someView.alpha = 1;
}
}
}
Why is that, I would think that it doesn't matter which way I reference the weak self since it should "just" optionally unwrap self? correctly. For context this is done in a UICellView which is deallocated when I leave the UICollectionViewController
EDIT: Filed a bug with apple: #23492648
I think the problem here is that self is special. You've passed the reference to self weakly into the anonymous function to prevent a retain cycle, but there isn't really an Optional wrapping self in this story. Thus, the syntactic sugar self?.someView.alpha = 1 — and remember, it is merely syntactic sugar — doesn't work.
It may be that Apple will regard this as a bug; or maybe not. But either way, the solution is to do formulaically exactly what you are doing in the second example: do the weak-strong dance explicitly.