自定义按钮内存问题中的内存泄漏

memory leaking in custom button memory problems

试图找出为什么没有在 OptionsButton 中调用 deinit class

func getActionButtonView(delegate: DiscoveryActionViewDelegate) -> UIView {
    switch delegate.actionType {
case .showVariants:
    let optionButton = OptionsButton(frame: CGRect(x: 0, y: 0, width: 60, height: 20))
          optionButton.setup()
          optionButton.selectOptionsAction = {
            delegate.showVariants(completionBlock: {  _ in
              optionButton.hideLoader()
            })
          }
          return optionButton
}

BaseButton 是 HardButton 的父级,而 HardButton 是 OptionsButton 的父级

class OptionsButton: HardButton {
  var selectOptionsAction: () -> Void = {}

  func setup() {
    setTitleColor(UIColor.color(227, 0, 77), for: .normal)
    backgroundColor = .white
    titleLabel?.font = UIFont.font(weight: .semiBold, style: .footnote1)
    setTitle("list_screen_selectOption_button".localized, for: .normal)
    addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    borderColor = UIColor.color(227, 0, 77)
    progressColor = UIColor.color(227, 0, 77)
    borderWidth = 1
    cornerRadius = 4
  }

  @objc func buttonAction(sender: HardButton) {
    self.displayLoader()
    self.selectOptionsAction()
  }
    
    deinit {
        print("deinit OptionsBtn")
    }

}

谁能帮我找出原因或告诉我我做错了什么? is/are 泄漏的地方

编辑 1-- 更多代码:

enum DiscoveryActionType {
  case cartAction
  case showVariants
  case recommendationCartAction
}

protocol DiscoveryActionViewDelegate: AnyObject {
  func showVariants(completionBlock: @escaping (Bool) -> Void)
  var actionType: DiscoveryActionType { get }
}

您应该通过“调试内存图”进行确认,但是 selectOptionsAction 是一个引用自身的闭包(delegate 也是)。这就是经典的“强引用循环”。

可以在捕获列表中使用 weak 引用来打破强引用循环:

let optionButton = OptionsButton(frame: …)
…
optionButton.selectOptionsAction = { [weak delegate] in
    delegate?.showVariants { [weak optionButton] _ in
        optionButton?.hideLoader()
    }
}

您要确保按钮不会对自身保持强引用。我也确保使用 weakdelegate 的引用。

细节可能有所不同,但希望这能说明这个想法。使用“调试内存图”来确定是什么保持对相关对象的强引用,并在捕获列表中使用 weak 引用来打破强引用循环。


有关如何使用“调试内存图”功能的示例,请参见