2

In other stack overflow questions, it was emphasized that the capture [weak self] should be used for closures that aren't owned by the class because self could be nil before the closure completes. An alternative when the closure is owned by the class itself is [unowned self].

My question is do I need to use [unowned self] when the function I pass as a parameter is an instance method of the current class?

Example

import RxSwift

class Person {
    var name = "Default name"

    class func getPersons() -> Observable<Person> {
        // ...
    }


}

class MyController: UIViewController {
    let disposeBag = DisposeBag()

    // I know this right
    func unownedDisplayPeople() {

        Person.getPersons()
            .subscribeNext { [unowned self ] person in
                self.displayName(person)
            }
            .addDisposableToBag(disposeBag)
    }

    // But what about this?
    func whatAboutThisDisplayPeople() {

        Person.getPersons()
            .subscribeNext(displayName)
            .addDisposableToBag(disposeBag)
    }

    // Or this?
    func orThisDisplayPeople() {

        Person.getPersons()
            .subscribeNext(self.displayName)
            .addDisposableToBag(disposeBag)
    }

    func displayName(person: Person) {
        print("Person name is \(person.name)")
    }
}

If I still need to think about the reference counting when I just pass an instance method, how do I do it? Where do i put the [unowned self]? Or is it considered [unowned self] already when I just pass the instance method?

Community
  • 1
  • 1
dsapalo
  • 1,819
  • 2
  • 19
  • 37
  • Related: [How to remove strong reference cycle from closure from method?](http://stackoverflow.com/q/39899051/2976878) – Hamish Nov 14 '16 at 10:42
  • How you can do using [RxSwiftExt](https://github.com/RxSwiftCommunity/RxSwiftExt) — [example](https://twitter.com/abdurahimjauzee/status/1005157382643699716) – Jauzee Jun 09 '18 at 05:06

1 Answers1

7

Unfortunately, passing an instance method to subscribeNext will retain self. To be more generic, storing a reference to an instance method will increase the retain count of the instance.

let instance = ReferenceType()
print(CFGetRetainCount(instance)) // 1

let methodReference = instance.method
print(CFGetRetainCount(instance)) // 2

The only solution here is do what you have done in unownedDisplayPeople.

let instance = ReferenceType()
print(CFGetRetainCount(instance)) // 1

let methodReference = { [unowned instance] in instance.method() }
print(CFGetRetainCount(instance)) // 1
tomahh
  • 13,441
  • 3
  • 49
  • 70
  • Thank you for clarifying this tomahh. I'm just bothered by the syntax cause it doesn't look pretty at all. :( But I guess I'll have to make do with it to prevent memory leaks. – dsapalo Nov 14 '16 at 07:50
  • 1
    Yeah, I hate it too. Maybe there's a way we could create a `subscribeWeaklyNext` version of `subscribeNext` that does not change the retain count... – tomahh Nov 14 '16 at 07:52
  • 1
    So, I fiddled around a bit in the swift playground and hit a wall. Closures cannot be made `weak` as it only applies to class and class-bound protocols. I guess self is capture before the function call (that accepts the closure) is made. Seems like we are stuck with this "non-optimal" syntax :/ – tomahh Nov 14 '16 at 08:07
  • Additional reading: http://blog.stablekernel.com/how-to-prevent-memory-leaks-in-swift-closures – dsapalo Feb 10 '17 at 02:03