为什么此合并订阅未在自定义ViewModifier中取消分配?

时间:2020-07-08 01:39:07

标签: swift swiftui combine

assign的文档中,其内容如下...

此操作员创建的Subscribers / Assign实例维护一个 对对象的强引用,并在上游时将其设置为nil 发布者完成(正常或有错误)。

ViewModifierassign方法下面的subscribeToKeyboardChanges()中,它是指self,但self是这里的结构,因此无法创建强引用。

  • 为什么subscribeToKeyboardChanges()中的订阅没有立即被释放?
  • 幕后的实际情况是什么?
struct KeyboardHandler: ViewModifier {

    @State private var keyboardHeight: CGFloat = 0

    func body(content: Content) -> some View {
        content
            .padding(.bottom, self.keyboardHeight)
            .animation(.default)
            .onAppear(perform: subscribeToKeyboardChanges)
    }

    private let keyboardWillShow = NotificationCenter.default
        .publisher(for: UIResponder.keyboardWillShowNotification)
        .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect }
        .map { $0.height }

    private let keyboardWillHide =  NotificationCenter.default
        .publisher(for: UIResponder.keyboardWillHideNotification)
        .map { _ in CGFloat.zero }

    private func subscribeToKeyboardChanges() {
        _ = Publishers.Merge(keyboardWillShow, keyboardWillHide)
            .subscribe(on: DispatchQueue.main)
            .assign(to: \.self.keyboardHeight, on: self)
    }
}

1 个答案:

答案 0 :(得分:0)

我相信您指的是错误的功能描述。这是正确的一个:

分配(至:开:)

将发布者的输出分配给对象的属性。

...

返回值

AnyCancellable实例。如果没有,请在此实例上调用cancel() 不再希望发布者自动分配属性。 取消初始化此实例也会取消自动分配。

因此,在您的subscribeToKeyboardChanges示例代码中,预期在函数完成后将取消订阅。您必须牢记从AnyCancellable返回的assign才能将预订保留在内存中。

编辑:

似乎在这一行assign复制了self并将其保存在内存中,直到调用cancel()

        .assign(to: \.self.keyboardHeight, on: self)

因此,使用View视图修饰符的KeyboardHandler将永远不会被取消分配订阅,并且最终将在导航期间使内存膨胀。例如,这是经过3次导航后仍在内存中查看KeyboardHandler的3个实例的屏幕截图。

enter image description here