首页 > 解决方案 > 当 self 被释放时,Unowned self 不会导致运行时中断?

问题描述

我对 swift 中的内存管理相当熟悉,而且我知道如果在捕获闭包中我们使用 [unowned self] 代码会中断,如果 self 变为 nil 并且我们在 self 上调用一些方法。仍然我一直在涉足组合并找到了 curios 案例,self 变为 nil,但代码永远不会中断。我试图对其进行更多测试,以解释正在发生的事情,但不能。这是示例:

class DetailsViewController: UIViewController {

var subject: PassthroughSubject<Int, Never>!
var localIntHolder: Int!
private var subscriptions = Set<AnyCancellable>()

override func viewDidLoad() {
    super.viewDidLoad()
    
    subject
        .flatMap { [unowned self] value in
            self.completionPublisher()
        }
        .map({ [unowned self] value in
            self.increaseValue(value)
        })
        .sink { [unowned self] value in
            print("\(value)")
            self.localIntHolder = value
        }
        .store(in: &subscriptions)
    
    subject.send(22)
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        self.dismiss(animated: true, completion: nil)
    }
}

private func increaseValue(_ value: Int) -> Int {
    return value + 1
}

deinit {
    print("deinit")
}

private func completionPublisher() -> AnyPublisher<Int, Never> {
    return Future<Int, Never> { promise in
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            promise(.success(10))
        }
    }
    .eraseToAnyPublisher()
}
}

这是主视图控制器的设置:

let subjectInt = PassthroughSubject<Int, Never>()

override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let controller = DetailsViewController()
        controller.subject = subjectInt
        present(controller, animated: true, completion: nil)
    }

现在这是一个简单的例子,发送者将发送值,未来将延迟 10 秒。在发生这种情况时,我在其中解除分配控制器。我想代码会中断,但什么也没发生,控制器被释放,管道的其余部分从未执行。

有没有我想念的组合魔法?

标签: swiftmemory-managementautomatic-ref-countingcombine

解决方案


存入subscriptions_

.store(in: &subscriptions)

subscriptions确保订阅不会立即释放,因为控制器通过其变量拥有它们(强烈引用它们) 。

当控制器被释放时,subscriptions也是deallocated. 在解除分配期间订阅也被取消,因此整个链被取消(包括异步请求,例如)。这意味着订阅将不再运行,并且他们无法访问该[unowned self].


推荐阅读