Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding strong reference when passing a method to a function

When passing a method to a function that takes a closure, I can use either someFunc(closure: someMethod) orsomeFunc() { [unowned self] in self.someMethod() }`.

The first one is shorter but makes a strong reference. How can I use it while avoiding this strong reference?

Here is a demo with both the leaking one and the good one: https://swiftlang.ng.bluemix.net/#/repl/581ccd3a0bdc661a6c566347

import Foundation

private var instanceCounter = 0

class Leak : NSObject {

    override init() {
        super.init()
        instanceCounter += 1
    }

    deinit {
        instanceCounter -= 1
    }
}

class OnFunctionLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil,
                                               usingBlock: doNothing)
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

class OnClosureLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil) { [unowned self] notif in
            self.doNothing(notif)
        }
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

var onFunctionLeak: OnFunctionLeak? = OnFunctionLeak()
onFunctionLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

instanceCounter = 0
var onClosureLeak: OnClosureLeak? = OnClosureLeak()
onClosureLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

The shorter choice is on line 26 and if I replace doNothing by { [unowned self] notif in self.doNothing(notif) }, the strong reference is gone.

Any ideas?

like image 378
Dam Avatar asked Dec 13 '25 02:12

Dam


1 Answers

How can I use it while avoiding this strong reference?

You can't.

Only an anonymous function defined inline (at the point of usage) can have a capture list (such as [unowned self]). Thus, only an anonymous function can provide the functionality you are asking for. A function defined with func simply cannot do it.

That's just a fact about Swift.

(There are probably underlying reasons for it; I suspect that the reasons have to do with storage. A func function is stored statically in some way. But an anonymous function defined inline is not; it comes into being at exactly the moment it is passed to the callee. But that's just a guess, and a rather vague guess at that.)

like image 168
matt Avatar answered Dec 15 '25 18:12

matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!