Using 'self' on RxSwift closures… What abo

2020-04-17 05:24发布

问题:

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?

回答1:

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